package com.chenju.javastatic.utils;

import com.github.difflib.DiffUtils;
import com.github.difflib.UnifiedDiffUtils;
import com.github.difflib.patch.Patch;

import java.util.Arrays;
import java.util.List;

public class EasyDiffUtils {
    public static String diff(String source, String target){
        source = source == null ? "" : source;
        target = target == null ? "" : target;
        List<String> sourceList = Arrays.asList(source.split("\n"));
        List<String> targetList = Arrays.asList(target.split("\n"));
        // 生成diff
        Patch<String> patch = DiffUtils.diff(sourceList, targetList);

        // 将diff转换为统一格式的diff字符串
        List<String> unifiedDiff = UnifiedDiffUtils.generateUnifiedDiff("master", "feature", sourceList, patch, 0);

        // 输出diff字符串
        System.out.println(String.join("\n", unifiedDiff));
        return String.join("\n", unifiedDiff);
    }

    public static void main(String[] args) {
        System.out.println(diff("\"use strict\";\n" +
                "// Object.defineProperty(exports, \"__esModule\", { value: true });\n" +
                "// @ts-ignore\n" +
                "// var d3 = require(\"d3\");\n" +
                "import * as d3 from \"d3\";\n" +
                "// require(\"./styles/styles.css\");\n" +
                "import \"./styles/styles.css\";\n" +
                "// require(\"font-awesome/css/font-awesome.css\");\n" +
                "// var interface_1 = require(\"./interfaces/interface\");\n" +
                "// import interface_1 from \"./interfaces/interface\";\n" +
                "function Neo4jD3() {\n" +
                "  var container,\n" +
                "    info,\n" +
                "    node,\n" +
                "    nodes,\n" +
                "    relationship,\n" +
                "    relationshipOutline,\n" +
                "    relationshipOverlay,\n" +
                "    relationshipText,\n" +
                "    relationships,\n" +
                "    selector,\n" +
                "    simulation,\n" +
                "    svg,\n" +
                "    svgNodes,\n" +
                "    svgRelationships,\n" +
                "    svgScale,\n" +
                "    svgTranslate,\n" +
                "    classes2colors = {},\n" +
                "    justLoaded = false,\n" +
                "    numClasses = 0,\n" +
                "    options = {\n" +
                "      arrowSize: 4,\n" +
                "      colors: [\n" +
                "        \"#68bdf6\",\n" +
                "        \"#6dce9e\",\n" +
                "        \"#faafc2\",\n" +
                "        \"#f2baf6\",\n" +
                "        \"#ff928c\",\n" +
                "        \"#fcea7e\",\n" +
                "        \"#ffc766\",\n" +
                "        \"#405f9e\",\n" +
                "        \"#a5abb6\",\n" +
                "        \"#78cecb\",\n" +
                "        \"#b88cbb\",\n" +
                "        \"#ced2d9\",\n" +
                "        \"#e84646\",\n" +
                "        \"#fa5f86\",\n" +
                "        \"#ffab1a\",\n" +
                "        \"#fcda19\",\n" +
                "        \"#797b80\",\n" +
                "        \"#c9d96f\",\n" +
                "        \"#47991f\",\n" +
                "        \"#70edee\",\n" +
                "        \"#ff75ea\" // pink\n" +
                "      ],\n" +
                "      highlight: undefined,\n" +
                "      iconMap: {\n" +
                "        glass: \"f000\",\n" +
                "        music: \"f001\",\n" +
                "        search: \"f002\",\n" +
                "        \"envelope-o\": \"f003\",\n" +
                "        heart: \"f004\",\n" +
                "        star: \"f005\",\n" +
                "        \"star-o\": \"f006\",\n" +
                "        user: \"f007\",\n" +
                "        film: \"f008\",\n" +
                "        \"th-large\": \"f009\",\n" +
                "        th: \"f00a\",\n" +
                "        \"th-list\": \"f00b\",\n" +
                "        check: \"f00c\",\n" +
                "        \"remove,close,times\": \"f00d\",\n" +
                "        \"search-plus\": \"f00e\",\n" +
                "        \"search-minus\": \"f010\",\n" +
                "        \"power-off\": \"f011\",\n" +
                "        signal: \"f012\",\n" +
                "        \"gear,cog\": \"f013\",\n" +
                "        \"trash-o\": \"f014\",\n" +
                "        home: \"f015\",\n" +
                "        \"file-o\": \"f016\",\n" +
                "        \"clock-o\": \"f017\",\n" +
                "        road: \"f018\",\n" +
                "        download: \"f019\",\n" +
                "        \"arrow-circle-o-down\": \"f01a\",\n" +
                "        \"arrow-circle-o-up\": \"f01b\",\n" +
                "        inbox: \"f01c\",\n" +
                "        \"play-circle-o\": \"f01d\",\n" +
                "        \"rotate-right,repeat\": \"f01e\",\n" +
                "        refresh: \"f021\",\n" +
                "        \"list-alt\": \"f022\",\n" +
                "        lock: \"f023\",\n" +
                "        flag: \"f024\",\n" +
                "        headphones: \"f025\",\n" +
                "        \"volume-off\": \"f026\",\n" +
                "        \"volume-down\": \"f027\",\n" +
                "        \"volume-up\": \"f028\",\n" +
                "        qrcode: \"f029\",\n" +
                "        barcode: \"f02a\",\n" +
                "        tag: \"f02b\",\n" +
                "        tags: \"f02c\",\n" +
                "        book: \"f02d\",\n" +
                "        bookmark: \"f02e\",\n" +
                "        print: \"f02f\",\n" +
                "        camera: \"f030\",\n" +
                "        font: \"f031\",\n" +
                "        bold: \"f032\",\n" +
                "        italic: \"f033\",\n" +
                "        \"text-height\": \"f034\",\n" +
                "        \"text-width\": \"f035\",\n" +
                "        \"align-left\": \"f036\",\n" +
                "        \"align-center\": \"f037\",\n" +
                "        \"align-right\": \"f038\",\n" +
                "        \"align-justify\": \"f039\",\n" +
                "        list: \"f03a\",\n" +
                "        \"dedent,outdent\": \"f03b\",\n" +
                "        indent: \"f03c\",\n" +
                "        \"video-camera\": \"f03d\",\n" +
                "        \"photo,image,picture-o\": \"f03e\",\n" +
                "        pencil: \"f040\",\n" +
                "        \"map-marker\": \"f041\",\n" +
                "        adjust: \"f042\",\n" +
                "        tint: \"f043\",\n" +
                "        \"edit,pencil-square-o\": \"f044\",\n" +
                "        \"share-square-o\": \"f045\",\n" +
                "        \"check-square-o\": \"f046\",\n" +
                "        arrows: \"f047\",\n" +
                "        \"step-backward\": \"f048\",\n" +
                "        \"fast-backward\": \"f049\",\n" +
                "        backward: \"f04a\",\n" +
                "        play: \"f04b\",\n" +
                "        pause: \"f04c\",\n" +
                "        stop: \"f04d\",\n" +
                "        forward: \"f04e\",\n" +
                "        \"fast-forward\": \"f050\",\n" +
                "        \"step-forward\": \"f051\",\n" +
                "        eject: \"f052\",\n" +
                "        \"chevron-left\": \"f053\",\n" +
                "        \"chevron-right\": \"f054\",\n" +
                "        \"plus-circle\": \"f055\",\n" +
                "        \"minus-circle\": \"f056\",\n" +
                "        \"times-circle\": \"f057\",\n" +
                "        \"check-circle\": \"f058\",\n" +
                "        \"question-circle\": \"f059\",\n" +
                "        \"info-circle\": \"f05a\",\n" +
                "        crosshairs: \"f05b\",\n" +
                "        \"times-circle-o\": \"f05c\",\n" +
                "        \"check-circle-o\": \"f05d\",\n" +
                "        ban: \"f05e\",\n" +
                "        \"arrow-left\": \"f060\",\n" +
                "        \"arrow-right\": \"f061\",\n" +
                "        \"arrow-up\": \"f062\",\n" +
                "        \"arrow-down\": \"f063\",\n" +
                "        \"mail-forward,share\": \"f064\",\n" +
                "        expand: \"f065\",\n" +
                "        compress: \"f066\",\n" +
                "        plus: \"f067\",\n" +
                "        minus: \"f068\",\n" +
                "        asterisk: \"f069\",\n" +
                "        \"exclamation-circle\": \"f06a\",\n" +
                "        gift: \"f06b\",\n" +
                "        leaf: \"f06c\",\n" +
                "        fire: \"f06d\",\n" +
                "        eye: \"f06e\",\n" +
                "        \"eye-slash\": \"f070\",\n" +
                "        \"warning,exclamation-triangle\": \"f071\",\n" +
                "        plane: \"f072\",\n" +
                "        calendar: \"f073\",\n" +
                "        random: \"f074\",\n" +
                "        comment: \"f075\",\n" +
                "        magnet: \"f076\",\n" +
                "        \"chevron-up\": \"f077\",\n" +
                "        \"chevron-down\": \"f078\",\n" +
                "        retweet: \"f079\",\n" +
                "        \"shopping-cart\": \"f07a\",\n" +
                "        folder: \"f07b\",\n" +
                "        \"folder-open\": \"f07c\",\n" +
                "        \"arrows-v\": \"f07d\",\n" +
                "        \"arrows-h\": \"f07e\",\n" +
                "        \"bar-chart-o,bar-chart\": \"f080\",\n" +
                "        \"twitter-square\": \"f081\",\n" +
                "        \"facebook-square\": \"f082\",\n" +
                "        \"camera-retro\": \"f083\",\n" +
                "        key: \"f084\",\n" +
                "        \"gears,cogs\": \"f085\",\n" +
                "        comments: \"f086\",\n" +
                "        \"thumbs-o-up\": \"f087\",\n" +
                "        \"thumbs-o-down\": \"f088\",\n" +
                "        \"star-half\": \"f089\",\n" +
                "        \"heart-o\": \"f08a\",\n" +
                "        \"sign-out\": \"f08b\",\n" +
                "        \"linkedin-square\": \"f08c\",\n" +
                "        \"thumb-tack\": \"f08d\",\n" +
                "        \"external-link\": \"f08e\",\n" +
                "        \"sign-in\": \"f090\",\n" +
                "        trophy: \"f091\",\n" +
                "        \"github-square\": \"f092\",\n" +
                "        upload: \"f093\",\n" +
                "        \"lemon-o\": \"f094\",\n" +
                "        phone: \"f095\",\n" +
                "        \"square-o\": \"f096\",\n" +
                "        \"bookmark-o\": \"f097\",\n" +
                "        \"phone-square\": \"f098\",\n" +
                "        twitter: \"f099\",\n" +
                "        \"facebook-f,facebook\": \"f09a\",\n" +
                "        github: \"f09b\",\n" +
                "        unlock: \"f09c\",\n" +
                "        \"credit-card\": \"f09d\",\n" +
                "        \"feed,rss\": \"f09e\",\n" +
                "        \"hdd-o\": \"f0a0\",\n" +
                "        bullhorn: \"f0a1\",\n" +
                "        bell: \"f0f3\",\n" +
                "        certificate: \"f0a3\",\n" +
                "        \"hand-o-right\": \"f0a4\",\n" +
                "        \"hand-o-left\": \"f0a5\",\n" +
                "        \"hand-o-up\": \"f0a6\",\n" +
                "        \"hand-o-down\": \"f0a7\",\n" +
                "        \"arrow-circle-left\": \"f0a8\",\n" +
                "        \"arrow-circle-right\": \"f0a9\",\n" +
                "        \"arrow-circle-up\": \"f0aa\",\n" +
                "        \"arrow-circle-down\": \"f0ab\",\n" +
                "        globe: \"f0ac\",\n" +
                "        wrench: \"f0ad\",\n" +
                "        tasks: \"f0ae\",\n" +
                "        filter: \"f0b0\",\n" +
                "        briefcase: \"f0b1\",\n" +
                "        \"arrows-alt\": \"f0b2\",\n" +
                "        \"group,users\": \"f0c0\",\n" +
                "        \"chain,link\": \"f0c1\",\n" +
                "        cloud: \"f0c2\",\n" +
                "        flask: \"f0c3\",\n" +
                "        \"cut,scissors\": \"f0c4\",\n" +
                "        \"copy,files-o\": \"f0c5\",\n" +
                "        paperclip: \"f0c6\",\n" +
                "        \"save,floppy-o\": \"f0c7\",\n" +
                "        square: \"f0c8\",\n" +
                "        \"navicon,reorder,bars\": \"f0c9\",\n" +
                "        \"list-ul\": \"f0ca\",\n" +
                "        \"list-ol\": \"f0cb\",\n" +
                "        strikethrough: \"f0cc\",\n" +
                "        underline: \"f0cd\",\n" +
                "        table: \"f0ce\",\n" +
                "        magic: \"f0d0\",\n" +
                "        truck: \"f0d1\",\n" +
                "        pinterest: \"f0d2\",\n" +
                "        \"pinterest-square\": \"f0d3\",\n" +
                "        \"google-plus-square\": \"f0d4\",\n" +
                "        \"google-plus\": \"f0d5\",\n" +
                "        money: \"f0d6\",\n" +
                "        \"caret-down\": \"f0d7\",\n" +
                "        \"caret-up\": \"f0d8\",\n" +
                "        \"caret-left\": \"f0d9\",\n" +
                "        \"caret-right\": \"f0da\",\n" +
                "        columns: \"f0db\",\n" +
                "        \"unsorted,sort\": \"f0dc\",\n" +
                "        \"sort-down,sort-desc\": \"f0dd\",\n" +
                "        \"sort-up,sort-asc\": \"f0de\",\n" +
                "        envelope: \"f0e0\",\n" +
                "        linkedin: \"f0e1\",\n" +
                "        \"rotate-left,undo\": \"f0e2\",\n" +
                "        \"legal,gavel\": \"f0e3\",\n" +
                "        \"dashboard,tachometer\": \"f0e4\",\n" +
                "        \"comment-o\": \"f0e5\",\n" +
                "        \"comments-o\": \"f0e6\",\n" +
                "        \"flash,bolt\": \"f0e7\",\n" +
                "        sitemap: \"f0e8\",\n" +
                "        umbrella: \"f0e9\",\n" +
                "        \"paste,clipboard\": \"f0ea\",\n" +
                "        \"lightbulb-o\": \"f0eb\",\n" +
                "        exchange: \"f0ec\",\n" +
                "        \"cloud-download\": \"f0ed\",\n" +
                "        \"cloud-upload\": \"f0ee\",\n" +
                "        \"user-md\": \"f0f0\",\n" +
                "        stethoscope: \"f0f1\",\n" +
                "        suitcase: \"f0f2\",\n" +
                "        \"bell-o\": \"f0a2\",\n" +
                "        coffee: \"f0f4\",\n" +
                "        cutlery: \"f0f5\",\n" +
                "        \"file-text-o\": \"f0f6\",\n" +
                "        \"building-o\": \"f0f7\",\n" +
                "        \"hospital-o\": \"f0f8\",\n" +
                "        ambulance: \"f0f9\",\n" +
                "        medkit: \"f0fa\",\n" +
                "        \"fighter-jet\": \"f0fb\",\n" +
                "        beer: \"f0fc\",\n" +
                "        \"h-square\": \"f0fd\",\n" +
                "        \"plus-square\": \"f0fe\",\n" +
                "        \"angle-double-left\": \"f100\",\n" +
                "        \"angle-double-right\": \"f101\",\n" +
                "        \"angle-double-up\": \"f102\",\n" +
                "        \"angle-double-down\": \"f103\",\n" +
                "        \"angle-left\": \"f104\",\n" +
                "        \"angle-right\": \"f105\",\n" +
                "        \"angle-up\": \"f106\",\n" +
                "        \"angle-down\": \"f107\",\n" +
                "        desktop: \"f108\",\n" +
                "        laptop: \"f109\",\n" +
                "        tablet: \"f10a\",\n" +
                "        \"mobile-phone,mobile\": \"f10b\",\n" +
                "        \"circle-o\": \"f10c\",\n" +
                "        \"quote-left\": \"f10d\",\n" +
                "        \"quote-right\": \"f10e\",\n" +
                "        spinner: \"f110\",\n" +
                "        circle: \"f111\",\n" +
                "        \"mail-reply,reply\": \"f112\",\n" +
                "        \"github-alt\": \"f113\",\n" +
                "        \"folder-o\": \"f114\",\n" +
                "        \"folder-open-o\": \"f115\",\n" +
                "        \"smile-o\": \"f118\",\n" +
                "        \"frown-o\": \"f119\",\n" +
                "        \"meh-o\": \"f11a\",\n" +
                "        gamepad: \"f11b\",\n" +
                "        \"keyboard-o\": \"f11c\",\n" +
                "        \"flag-o\": \"f11d\",\n" +
                "        \"flag-checkered\": \"f11e\",\n" +
                "        terminal: \"f120\",\n" +
                "        code: \"f121\",\n" +
                "        \"mail-reply-all,reply-all\": \"f122\",\n" +
                "        \"star-half-empty,star-half-full,star-half-o\": \"f123\",\n" +
                "        \"location-arrow\": \"f124\",\n" +
                "        crop: \"f125\",\n" +
                "        \"code-fork\": \"f126\",\n" +
                "        \"unlink,chain-broken\": \"f127\",\n" +
                "        question: \"f128\",\n" +
                "        info: \"f129\",\n" +
                "        exclamation: \"f12a\",\n" +
                "        superscript: \"f12b\",\n" +
                "        subscript: \"f12c\",\n" +
                "        eraser: \"f12d\",\n" +
                "        \"puzzle-piece\": \"f12e\",\n" +
                "        microphone: \"f130\",\n" +
                "        \"microphone-slash\": \"f131\",\n" +
                "        shield: \"f132\",\n" +
                "        \"calendar-o\": \"f133\",\n" +
                "        \"fire-extinguisher\": \"f134\",\n" +
                "        rocket: \"f135\",\n" +
                "        maxcdn: \"f136\",\n" +
                "        \"chevron-circle-left\": \"f137\",\n" +
                "        \"chevron-circle-right\": \"f138\",\n" +
                "        \"chevron-circle-up\": \"f139\",\n" +
                "        \"chevron-circle-down\": \"f13a\",\n" +
                "        html5: \"f13b\",\n" +
                "        css3: \"f13c\",\n" +
                "        anchor: \"f13d\",\n" +
                "        \"unlock-alt\": \"f13e\",\n" +
                "        bullseye: \"f140\",\n" +
                "        \"ellipsis-h\": \"f141\",\n" +
                "        \"ellipsis-v\": \"f142\",\n" +
                "        \"rss-square\": \"f143\",\n" +
                "        \"play-circle\": \"f144\",\n" +
                "        ticket: \"f145\",\n" +
                "        \"minus-square\": \"f146\",\n" +
                "        \"minus-square-o\": \"f147\",\n" +
                "        \"level-up\": \"f148\",\n" +
                "        \"level-down\": \"f149\",\n" +
                "        \"check-square\": \"f14a\",\n" +
                "        \"pencil-square\": \"f14b\",\n" +
                "        \"external-link-square\": \"f14c\",\n" +
                "        \"share-square\": \"f14d\",\n" +
                "        compass: \"f14e\",\n" +
                "        \"toggle-down,caret-square-o-down\": \"f150\",\n" +
                "        \"toggle-up,caret-square-o-up\": \"f151\",\n" +
                "        \"toggle-right,caret-square-o-right\": \"f152\",\n" +
                "        \"euro,eur\": \"f153\",\n" +
                "        gbp: \"f154\",\n" +
                "        \"dollar,usd\": \"f155\",\n" +
                "        \"rupee,inr\": \"f156\",\n" +
                "        \"cny,rmb,yen,jpy\": \"f157\",\n" +
                "        \"ruble,rouble,rub\": \"f158\",\n" +
                "        \"won,krw\": \"f159\",\n" +
                "        \"bitcoin,btc\": \"f15a\",\n" +
                "        file: \"f15b\",\n" +
                "        \"file-text\": \"f15c\",\n" +
                "        \"sort-alpha-asc\": \"f15d\",\n" +
                "        \"sort-alpha-desc\": \"f15e\",\n" +
                "        \"sort-amount-asc\": \"f160\",\n" +
                "        \"sort-amount-desc\": \"f161\",\n" +
                "        \"sort-numeric-asc\": \"f162\",\n" +
                "        \"sort-numeric-desc\": \"f163\",\n" +
                "        \"thumbs-up\": \"f164\",\n" +
                "        \"thumbs-down\": \"f165\",\n" +
                "        \"youtube-square\": \"f166\",\n" +
                "        youtube: \"f167\",\n" +
                "        xing: \"f168\",\n" +
                "        \"xing-square\": \"f169\",\n" +
                "        \"youtube-play\": \"f16a\",\n" +
                "        dropbox: \"f16b\",\n" +
                "        \"stack-overflow\": \"f16c\",\n" +
                "        instagram: \"f16d\",\n" +
                "        flickr: \"f16e\",\n" +
                "        adn: \"f170\",\n" +
                "        bitbucket: \"f171\",\n" +
                "        \"bitbucket-square\": \"f172\",\n" +
                "        tumblr: \"f173\",\n" +
                "        \"tumblr-square\": \"f174\",\n" +
                "        \"long-arrow-down\": \"f175\",\n" +
                "        \"long-arrow-up\": \"f176\",\n" +
                "        \"long-arrow-left\": \"f177\",\n" +
                "        \"long-arrow-right\": \"f178\",\n" +
                "        apple: \"f179\",\n" +
                "        windows: \"f17a\",\n" +
                "        android: \"f17b\",\n" +
                "        linux: \"f17c\",\n" +
                "        dribbble: \"f17d\",\n" +
                "        skype: \"f17e\",\n" +
                "        foursquare: \"f180\",\n" +
                "        trello: \"f181\",\n" +
                "        female: \"f182\",\n" +
                "        male: \"f183\",\n" +
                "        \"gittip,gratipay\": \"f184\",\n" +
                "        \"sun-o\": \"f185\",\n" +
                "        \"moon-o\": \"f186\",\n" +
                "        archive: \"f187\",\n" +
                "        bug: \"f188\",\n" +
                "        vk: \"f189\",\n" +
                "        weibo: \"f18a\",\n" +
                "        renren: \"f18b\",\n" +
                "        pagelines: \"f18c\",\n" +
                "        \"stack-exchange\": \"f18d\",\n" +
                "        \"arrow-circle-o-right\": \"f18e\",\n" +
                "        \"arrow-circle-o-left\": \"f190\",\n" +
                "        \"toggle-left,caret-square-o-left\": \"f191\",\n" +
                "        \"dot-circle-o\": \"f192\",\n" +
                "        wheelchair: \"f193\",\n" +
                "        \"vimeo-square\": \"f194\",\n" +
                "        \"turkish-lira,try\": \"f195\",\n" +
                "        \"plus-square-o\": \"f196\",\n" +
                "        \"space-shuttle\": \"f197\",\n" +
                "        slack: \"f198\",\n" +
                "        \"envelope-square\": \"f199\",\n" +
                "        wordpress: \"f19a\",\n" +
                "        openid: \"f19b\",\n" +
                "        \"institution,bank,university\": \"f19c\",\n" +
                "        \"mortar-board,graduation-cap\": \"f19d\",\n" +
                "        yahoo: \"f19e\",\n" +
                "        google: \"f1a0\",\n" +
                "        reddit: \"f1a1\",\n" +
                "        \"reddit-square\": \"f1a2\",\n" +
                "        \"stumbleupon-circle\": \"f1a3\",\n" +
                "        stumbleupon: \"f1a4\",\n" +
                "        delicious: \"f1a5\",\n" +
                "        digg: \"f1a6\",\n" +
                "        \"pied-piper-pp\": \"f1a7\",\n" +
                "        \"pied-piper-alt\": \"f1a8\",\n" +
                "        drupal: \"f1a9\",\n" +
                "        joomla: \"f1aa\",\n" +
                "        language: \"f1ab\",\n" +
                "        fax: \"f1ac\",\n" +
                "        building: \"f1ad\",\n" +
                "        child: \"f1ae\",\n" +
                "        paw: \"f1b0\",\n" +
                "        spoon: \"f1b1\",\n" +
                "        cube: \"f1b2\",\n" +
                "        cubes: \"f1b3\",\n" +
                "        behance: \"f1b4\",\n" +
                "        \"behance-square\": \"f1b5\",\n" +
                "        steam: \"f1b6\",\n" +
                "        \"steam-square\": \"f1b7\",\n" +
                "        recycle: \"f1b8\",\n" +
                "        \"automobile,car\": \"f1b9\",\n" +
                "        \"cab,taxi\": \"f1ba\",\n" +
                "        tree: \"f1bb\",\n" +
                "        spotify: \"f1bc\",\n" +
                "        deviantart: \"f1bd\",\n" +
                "        soundcloud: \"f1be\",\n" +
                "        database: \"f1c0\",\n" +
                "        \"file-pdf-o\": \"f1c1\",\n" +
                "        \"file-word-o\": \"f1c2\",\n" +
                "        \"file-excel-o\": \"f1c3\",\n" +
                "        \"file-powerpoint-o\": \"f1c4\",\n" +
                "        \"file-photo-o,file-picture-o,file-image-o\": \"f1c5\",\n" +
                "        \"file-zip-o,file-archive-o\": \"f1c6\",\n" +
                "        \"file-sound-o,file-audio-o\": \"f1c7\",\n" +
                "        \"file-movie-o,file-video-o\": \"f1c8\",\n" +
                "        \"file-code-o\": \"f1c9\",\n" +
                "        vine: \"f1ca\",\n" +
                "        codepen: \"f1cb\",\n" +
                "        jsfiddle: \"f1cc\",\n" +
                "        \"life-bouy,life-buoy,life-saver,support,life-ring\": \"f1cd\",\n" +
                "        \"circle-o-notch\": \"f1ce\",\n" +
                "        \"ra,resistance,rebel\": \"f1d0\",\n" +
                "        \"ge,empire\": \"f1d1\",\n" +
                "        \"git-square\": \"f1d2\",\n" +
                "        git: \"f1d3\",\n" +
                "        \"y-combinator-square,yc-square,hacker-news\": \"f1d4\",\n" +
                "        \"tencent-weibo\": \"f1d5\",\n" +
                "        qq: \"f1d6\",\n" +
                "        \"wechat,weixin\": \"f1d7\",\n" +
                "        \"send,paper-plane\": \"f1d8\",\n" +
                "        \"send-o,paper-plane-o\": \"f1d9\",\n" +
                "        history: \"f1da\",\n" +
                "        \"circle-thin\": \"f1db\",\n" +
                "        header: \"f1dc\",\n" +
                "        paragraph: \"f1dd\",\n" +
                "        sliders: \"f1de\",\n" +
                "        \"share-alt\": \"f1e0\",\n" +
                "        \"share-alt-square\": \"f1e1\",\n" +
                "        bomb: \"f1e2\",\n" +
                "        \"soccer-ball-o,futbol-o\": \"f1e3\",\n" +
                "        tty: \"f1e4\",\n" +
                "        binoculars: \"f1e5\",\n" +
                "        plug: \"f1e6\",\n" +
                "        slideshare: \"f1e7\",\n" +
                "        twitch: \"f1e8\",\n" +
                "        yelp: \"f1e9\",\n" +
                "        \"newspaper-o\": \"f1ea\",\n" +
                "        wifi: \"f1eb\",\n" +
                "        calculator: \"f1ec\",\n" +
                "        paypal: \"f1ed\",\n" +
                "        \"google-wallet\": \"f1ee\",\n" +
                "        \"cc-visa\": \"f1f0\",\n" +
                "        \"cc-mastercard\": \"f1f1\",\n" +
                "        \"cc-discover\": \"f1f2\",\n" +
                "        \"cc-amex\": \"f1f3\",\n" +
                "        \"cc-paypal\": \"f1f4\",\n" +
                "        \"cc-stripe\": \"f1f5\",\n" +
                "        \"bell-slash\": \"f1f6\",\n" +
                "        \"bell-slash-o\": \"f1f7\",\n" +
                "        trash: \"f1f8\",\n" +
                "        copyright: \"f1f9\",\n" +
                "        at: \"f1fa\",\n" +
                "        eyedropper: \"f1fb\",\n" +
                "        \"paint-brush\": \"f1fc\",\n" +
                "        \"birthday-cake\": \"f1fd\",\n" +
                "        \"area-chart\": \"f1fe\",\n" +
                "        \"pie-chart\": \"f200\",\n" +
                "        \"line-chart\": \"f201\",\n" +
                "        lastfm: \"f202\",\n" +
                "        \"lastfm-square\": \"f203\",\n" +
                "        \"toggle-off\": \"f204\",\n" +
                "        \"toggle-on\": \"f205\",\n" +
                "        bicycle: \"f206\",\n" +
                "        bus: \"f207\",\n" +
                "        ioxhost: \"f208\",\n" +
                "        angellist: \"f209\",\n" +
                "        cc: \"f20a\",\n" +
                "        \"shekel,sheqel,ils\": \"f20b\",\n" +
                "        meanpath: \"f20c\",\n" +
                "        buysellads: \"f20d\",\n" +
                "        connectdevelop: \"f20e\",\n" +
                "        dashcube: \"f210\",\n" +
                "        forumbee: \"f211\",\n" +
                "        leanpub: \"f212\",\n" +
                "        sellsy: \"f213\",\n" +
                "        shirtsinbulk: \"f214\",\n" +
                "        simplybuilt: \"f215\",\n" +
                "        skyatlas: \"f216\",\n" +
                "        \"cart-plus\": \"f217\",\n" +
                "        \"cart-arrow-down\": \"f218\",\n" +
                "        diamond: \"f219\",\n" +
                "        ship: \"f21a\",\n" +
                "        \"user-secret\": \"f21b\",\n" +
                "        motorcycle: \"f21c\",\n" +
                "        \"street-view\": \"f21d\",\n" +
                "        heartbeat: \"f21e\",\n" +
                "        venus: \"f221\",\n" +
                "        mars: \"f222\",\n" +
                "        mercury: \"f223\",\n" +
                "        \"intersex,transgender\": \"f224\",\n" +
                "        \"transgender-alt\": \"f225\",\n" +
                "        \"venus-double\": \"f226\",\n" +
                "        \"mars-double\": \"f227\",\n" +
                "        \"venus-mars\": \"f228\",\n" +
                "        \"mars-stroke\": \"f229\",\n" +
                "        \"mars-stroke-v\": \"f22a\",\n" +
                "        \"mars-stroke-h\": \"f22b\",\n" +
                "        neuter: \"f22c\",\n" +
                "        genderless: \"f22d\",\n" +
                "        \"facebook-official\": \"f230\",\n" +
                "        \"pinterest-p\": \"f231\",\n" +
                "        whatsapp: \"f232\",\n" +
                "        server: \"f233\",\n" +
                "        \"user-plus\": \"f234\",\n" +
                "        \"user-times\": \"f235\",\n" +
                "        \"hotel,bed\": \"f236\",\n" +
                "        viacoin: \"f237\",\n" +
                "        train: \"f238\",\n" +
                "        subway: \"f239\",\n" +
                "        medium: \"f23a\",\n" +
                "        \"yc,y-combinator\": \"f23b\",\n" +
                "        \"optin-monster\": \"f23c\",\n" +
                "        opencart: \"f23d\",\n" +
                "        expeditedssl: \"f23e\",\n" +
                "        \"battery-4,battery-full\": \"f240\",\n" +
                "        \"battery-3,battery-three-quarters\": \"f241\",\n" +
                "        \"battery-2,battery-half\": \"f242\",\n" +
                "        \"battery-1,battery-quarter\": \"f243\",\n" +
                "        \"battery-0,battery-empty\": \"f244\",\n" +
                "        \"mouse-pointer\": \"f245\",\n" +
                "        \"i-cursor\": \"f246\",\n" +
                "        \"object-group\": \"f247\",\n" +
                "        \"object-ungroup\": \"f248\",\n" +
                "        \"sticky-note\": \"f249\",\n" +
                "        \"sticky-note-o\": \"f24a\",\n" +
                "        \"cc-jcb\": \"f24b\",\n" +
                "        \"cc-diners-club\": \"f24c\",\n" +
                "        clone: \"f24d\",\n" +
                "        \"balance-scale\": \"f24e\",\n" +
                "        \"hourglass-o\": \"f250\",\n" +
                "        \"hourglass-1,hourglass-start\": \"f251\",\n" +
                "        \"hourglass-2,hourglass-half\": \"f252\",\n" +
                "        \"hourglass-3,hourglass-end\": \"f253\",\n" +
                "        hourglass: \"f254\",\n" +
                "        \"hand-grab-o,hand-rock-o\": \"f255\",\n" +
                "        \"hand-stop-o,hand-paper-o\": \"f256\",\n" +
                "        \"hand-scissors-o\": \"f257\",\n" +
                "        \"hand-lizard-o\": \"f258\",\n" +
                "        \"hand-spock-o\": \"f259\",\n" +
                "        \"hand-pointer-o\": \"f25a\",\n" +
                "        \"hand-peace-o\": \"f25b\",\n" +
                "        trademark: \"f25c\",\n" +
                "        registered: \"f25d\",\n" +
                "        \"creative-commons\": \"f25e\",\n" +
                "        gg: \"f260\",\n" +
                "        \"gg-circle\": \"f261\",\n" +
                "        tripadvisor: \"f262\",\n" +
                "        odnoklassniki: \"f263\",\n" +
                "        \"odnoklassniki-square\": \"f264\",\n" +
                "        \"get-pocket\": \"f265\",\n" +
                "        \"wikipedia-w\": \"f266\",\n" +
                "        safari: \"f267\",\n" +
                "        chrome: \"f268\",\n" +
                "        firefox: \"f269\",\n" +
                "        opera: \"f26a\",\n" +
                "        \"internet-explorer\": \"f26b\",\n" +
                "        \"tv,television\": \"f26c\",\n" +
                "        contao: \"f26d\",\n" +
                "        \"500px\": \"f26e\",\n" +
                "        amazon: \"f270\",\n" +
                "        \"calendar-plus-o\": \"f271\",\n" +
                "        \"calendar-minus-o\": \"f272\",\n" +
                "        \"calendar-times-o\": \"f273\",\n" +
                "        \"calendar-check-o\": \"f274\",\n" +
                "        industry: \"f275\",\n" +
                "        \"map-pin\": \"f276\",\n" +
                "        \"map-signs\": \"f277\",\n" +
                "        \"map-o\": \"f278\",\n" +
                "        map: \"f279\",\n" +
                "        commenting: \"f27a\",\n" +
                "        \"commenting-o\": \"f27b\",\n" +
                "        houzz: \"f27c\",\n" +
                "        vimeo: \"f27d\",\n" +
                "        \"black-tie\": \"f27e\",\n" +
                "        fonticons: \"f280\",\n" +
                "        \"reddit-alien\": \"f281\",\n" +
                "        edge: \"f282\",\n" +
                "        \"credit-card-alt\": \"f283\",\n" +
                "        codiepie: \"f284\",\n" +
                "        modx: \"f285\",\n" +
                "        \"fort-awesome\": \"f286\",\n" +
                "        usb: \"f287\",\n" +
                "        \"product-hunt\": \"f288\",\n" +
                "        mixcloud: \"f289\",\n" +
                "        scribd: \"f28a\",\n" +
                "        \"pause-circle\": \"f28b\",\n" +
                "        \"pause-circle-o\": \"f28c\",\n" +
                "        \"stop-circle\": \"f28d\",\n" +
                "        \"stop-circle-o\": \"f28e\",\n" +
                "        \"shopping-bag\": \"f290\",\n" +
                "        \"shopping-basket\": \"f291\",\n" +
                "        hashtag: \"f292\",\n" +
                "        bluetooth: \"f293\",\n" +
                "        \"bluetooth-b\": \"f294\",\n" +
                "        percent: \"f295\",\n" +
                "        gitlab: \"f296\",\n" +
                "        wpbeginner: \"f297\",\n" +
                "        wpforms: \"f298\",\n" +
                "        envira: \"f299\",\n" +
                "        \"universal-access\": \"f29a\",\n" +
                "        \"wheelchair-alt\": \"f29b\",\n" +
                "        \"question-circle-o\": \"f29c\",\n" +
                "        blind: \"f29d\",\n" +
                "        \"audio-description\": \"f29e\",\n" +
                "        \"volume-control-phone\": \"f2a0\",\n" +
                "        braille: \"f2a1\",\n" +
                "        \"assistive-listening-systems\": \"f2a2\",\n" +
                "        \"asl-interpreting,american-sign-language-interpreting\": \"f2a3\",\n" +
                "        \"deafness,hard-of-hearing,deaf\": \"f2a4\",\n" +
                "        glide: \"f2a5\",\n" +
                "        \"glide-g\": \"f2a6\",\n" +
                "        \"signing,sign-language\": \"f2a7\",\n" +
                "        \"low-vision\": \"f2a8\",\n" +
                "        viadeo: \"f2a9\",\n" +
                "        \"viadeo-square\": \"f2aa\",\n" +
                "        snapchat: \"f2ab\",\n" +
                "        \"snapchat-ghost\": \"f2ac\",\n" +
                "        \"snapchat-square\": \"f2ad\",\n" +
                "        \"pied-piper\": \"f2ae\",\n" +
                "        \"first-order\": \"f2b0\",\n" +
                "        yoast: \"f2b1\",\n" +
                "        themeisle: \"f2b2\",\n" +
                "        \"google-plus-circle,google-plus-official\": \"f2b3\",\n" +
                "        \"fa,font-awesome\": \"f2b4\"\n" +
                "      },\n" +
                "      icons: undefined,\n" +
                "      imageMap: {},\n" +
                "      images: undefined,\n" +
                "      infoPanel: true,\n" +
                "      minCollision: undefined,\n" +
                "      neo4jData: undefined,\n" +
                "      neo4jDataUrl: undefined,\n" +
                "      nodeOutlineFillColor: undefined,\n" +
                "      nodeRadius: 25,\n" +
                "      relationshipColor: \"red\",\n" +
                "      zoomFit: false\n" +
                "    },\n" +
                "    VERSION = \"1.0.1\";\n" +
                "  function appendGraph(container) {\n" +
                "    svg = container\n" +
                "      .append(\"svg\")\n" +
                "      .attr(\"width\", \"100%\")\n" +
                "      .attr(\"height\", \"100%\")\n" +
                "      .attr(\"class\", \"neo4jd3-graph\")\n" +
                "      .call(\n" +
                "        d3.zoom().on(\"zoom\", function (event) {\n" +
                "          var scale = event.transform.k,\n" +
                "            translate = [event.transform.x, event.transform.y];\n" +
                "          if (svgTranslate) {\n" +
                "            translate[0] += svgTranslate[0];\n" +
                "            translate[1] += svgTranslate[1];\n" +
                "          }\n" +
                "          if (svgScale) {\n" +
                "            scale *= svgScale;\n" +
                "          }\n" +
                "          svg.attr(\n" +
                "            \"transform\",\n" +
                "            \"translate(\" +\n" +
                "              translate[0] +\n" +
                "              \", \" +\n" +
                "              translate[1] +\n" +
                "              \") scale(\" +\n" +
                "              scale +\n" +
                "              \")\"\n" +
                "          );\n" +
                "        })\n" +
                "      )\n" +
                "      .on(\"dblclick.zoom\", null)\n" +
                "      .append(\"g\")\n" +
                "      .attr(\"width\", \"100%\")\n" +
                "      .attr(\"height\", \"100%\");\n" +
                "    svgRelationships = svg.append(\"g\").attr(\"class\", \"relationships\");\n" +
                "    svgNodes = svg.append(\"g\").attr(\"class\", \"nodes\");\n" +
                "  }\n" +
                "  function appendImageToNode(node) {\n" +
                "    return node\n" +
                "      .append(\"image\")\n" +
                "      .attr(\"height\", function (d) {\n" +
                "        return icon(d) ? \"24px\" : \"30px\";\n" +
                "      })\n" +
                "      .attr(\"x\", function (d) {\n" +
                "        return icon(d) ? \"5px\" : \"-15px\";\n" +
                "      })\n" +
                "      .attr(\"xlink:href\", function (d) {\n" +
                "        return image(d);\n" +
                "      })\n" +
                "      .attr(\"y\", function (d) {\n" +
                "        return icon(d) ? \"5px\" : \"-16px\";\n" +
                "      })\n" +
                "      .attr(\"width\", function (d) {\n" +
                "        return icon(d) ? \"24px\" : \"30px\";\n" +
                "      });\n" +
                "  }\n" +
                "  function appendInfoPanel(container) {\n" +
                "    return container.append(\"div\").attr(\"class\", \"neo4jd3-info\");\n" +
                "  }\n" +
                "  function appendInfoElement(cls, isNode, property, value) {\n" +
                "    var table = info\n" +
                "      .append(\"table\")\n" +
                "      .style(\"border-collapse\", \"collapse\")\n" +
                "      .style(\"width\", \"100%\");\n" +
                "    var row = table.append(\"tr\");\n" +
                "    if (!value) {\n" +
                "      row\n" +
                "        .append(\"td\")\n" +
                "        .attr(\"class\", cls)\n" +
                "        .style(\"border\", \"1px solid #dddddd\")\n" +
                "        .style(\"padding\", \"8px\")\n" +
                "        .style(\"width\", \"200px\")\n" +
                "        .style(\"text-wrap\", \"no-wrap\")\n" +
                "        .html(\"<strong>Name</strong>\");\n" +
                "      row\n" +
                "        .append(\"td\")\n" +
                "        .style(\"border\", \"1px solid #dddddd\")\n" +
                "        .style(\"padding\", \"8px\")\n" +
                "        .style(\"width\", \"auto\")\n" +
                "        .style(\"text-wrap\", \"no-wrap\")\n" +
                "        .html(\"<strong>\" + property + \"</strong>\");\n" +
                "      row\n" +
                "        .style(\"background-color\", function (d) {\n" +
                "          return options.nodeOutlineFillColor\n" +
                "            ? options.nodeOutlineFillColor\n" +
                "            : isNode\n" +
                "              ? class2color(property)\n" +
                "              : defaultColor();\n" +
                "        })\n" +
                "        .style(\"border-color\", function (d) {\n" +
                "          return options.nodeOutlineFillColor\n" +
                "            ? class2darkenColor(options.nodeOutlineFillColor)\n" +
                "            : isNode\n" +
                "              ? class2darkenColor(property)\n" +
                "              : defaultDarkenColor();\n" +
                "        })\n" +
                "        .style(\"color\", function (d) {\n" +
                "          return options.nodeOutlineFillColor\n" +
                "            ? class2darkenColor(options.nodeOutlineFillColor)\n" +
                "            : \"#fff\";\n" +
                "        });\n" +
                "    } else {\n" +
                "      row\n" +
                "        .append(\"td\")\n" +
                "        .attr(\"class\", cls)\n" +
                "        .style(\"border\", \"1px solid #dddddd\")\n" +
                "        .style(\"padding\", \"8px\")\n" +
                "        .style(\"width\", \"200px\")\n" +
                "        .style(\"text-wrap\", \"no-wrap\")\n" +
                "        .html(\"<strong>\" + property + \"</strong>\");\n" +
                "      row\n" +
                "        .append(\"td\")\n" +
                "        .style(\"border\", \"1px solid #dddddd\")\n" +
                "        .style(\"padding\", \"8px\")\n" +
                "        .style(\"width\", \"auto\")\n" +
                "        .style(\"text-wrap\", \"no-wrap\")\n" +
                "        .html(\"<strong>\" + value + \"</strong>\");\n" +
                "    }\n" +
                "  }\n" +
                "  function appendInfoElementClass(cls, node) {\n" +
                "    appendInfoElement(cls, true, node);\n" +
                "  }\n" +
                "  function appendInfoElementProperty(cls, property, value) {\n" +
                "    appendInfoElement(cls, false, property, value);\n" +
                "  }\n" +
                "  function appendInfoElementRelationship(cls, relationship) {\n" +
                "    appendInfoElement(cls, false, relationship);\n" +
                "  }\n" +
                "  function appendNode() {\n" +
                "    return node\n" +
                "      .enter()\n" +
                "      .append(\"g\")\n" +
                "      .attr(\"class\", function (d) {\n" +
                "        var highlight,\n" +
                "          i,\n" +
                "          classes = \"node\",\n" +
                "          label = d.labels[0];\n" +
                "        if (icon(d)) {\n" +
                "          classes += \" node-icon\";\n" +
                "        }\n" +
                "        if (image(d)) {\n" +
                "          classes += \" node-image\";\n" +
                "        }\n" +
                "        if (options.highlight) {\n" +
                "          for (i = 0; i < options.highlight.length; i++) {\n" +
                "            highlight = options.highlight[i];\n" +
                "            if (\n" +
                "              d.labels[0] === highlight.class &&\n" +
                "              d.properties[highlight.property] === highlight.value\n" +
                "            ) {\n" +
                "              classes += \" node-highlighted\";\n" +
                "              break;\n" +
                "            }\n" +
                "          }\n" +
                "        }\n" +
                "        return classes;\n" +
                "      })\n" +
                "      .on(\"click\", function (e, d) {\n" +
                "        d.fx = d.fy = null;\n" +
                "        if (typeof options.onNodeClick === \"function\") {\n" +
                "          options.onNodeClick(d);\n" +
                "        }\n" +
                "      })\n" +
                "      .on(\"dblclick\", function (e, d) {\n" +
                "        stickNode(e, d);\n" +
                "        if (typeof options.onNodeDoubleClick === \"function\") {\n" +
                "          options.onNodeDoubleClick(d);\n" +
                "        }\n" +
                "      })\n" +
                "      .on(\"mouseenter\", function (e, d) {\n" +
                "        if (info) {\n" +
                "          updateInfo(d);\n" +
                "        }\n" +
                "        if (typeof options.onNodeMouseEnter === \"function\") {\n" +
                "          options.onNodeMouseEnter(d);\n" +
                "        }\n" +
                "      })\n" +
                "      .on(\"mouseleave\", function (e, d) {\n" +
                "        if (info) {\n" +
                "          clearInfo(d);\n" +
                "        }\n" +
                "        if (typeof options.onNodeMouseLeave === \"function\") {\n" +
                "          options.onNodeMouseLeave(d);\n" +
                "        }\n" +
                "      })\n" +
                "      .call(\n" +
                "        d3\n" +
                "          .drag()\n" +
                "          .on(\"start\", dragStarted)\n" +
                "          .on(\"drag\", dragged)\n" +
                "          .on(\"end\", dragEnded)\n" +
                "      );\n" +
                "  }\n" +
                "  function appendNodeToGraph() {\n" +
                "    var n = appendNode();\n" +
                "    appendRingToNode(n);\n" +
                "    appendOutlineToNode(n);\n" +
                "    if (options.icons) {\n" +
                "      appendTextToNode(n);\n" +
                "    }\n" +
                "    if (options.images) {\n" +
                "      appendImageToNode(n);\n" +
                "    }\n" +
                "    return n;\n" +
                "  }\n" +
                "  function appendOutlineToNode(node) {\n" +
                "    return node\n" +
                "      .append(\"circle\")\n" +
                "      .attr(\"class\", \"outline\")\n" +
                "      .attr(\"r\", options.nodeRadius)\n" +
                "      .style(\"fill\", function (d) {\n" +
                "        return options.nodeOutlineFillColor\n" +
                "          ? options.nodeOutlineFillColor\n" +
                "          : class2color(d.labels[0]);\n" +
                "      })\n" +
                "      .style(\"stroke\", function (d) {\n" +
                "        return options.nodeOutlineFillColor\n" +
                "          ? class2darkenColor(options.nodeOutlineFillColor)\n" +
                "          : class2darkenColor(d.labels[0]);\n" +
                "      })\n" +
                "      .append(\"title\")\n" +
                "      .text(function (d) {\n" +
                "        return toString(d);\n" +
                "      });\n" +
                "  }\n" +
                "  function appendRingToNode(node) {\n" +
                "    return node\n" +
                "      .append(\"circle\")\n" +
                "      .attr(\"class\", \"ring\")\n" +
                "      .attr(\"r\", options.nodeRadius * 1.16)\n" +
                "      .append(\"title\")\n" +
                "      .text(function (d) {\n" +
                "        return toString(d);\n" +
                "      });\n" +
                "  }\n" +
                "  function appendTextToNode(node) {\n" +
                "    return node\n" +
                "      .append(\"text\")\n" +
                "      .attr(\"class\", function (d) {\n" +
                "        return \"text\" + (icon(d) ? \" icon\" : \"\");\n" +
                "      })\n" +
                "      .attr(\"fill\", \"#ffffff\")\n" +
                "      .attr(\"font-size\", function (d) {\n" +
                "        return icon(d) ? options.nodeRadius + \"px\" : \"10px\";\n" +
                "      })\n" +
                "      .attr(\"pointer-events\", \"none\")\n" +
                "      .attr(\"text-anchor\", \"middle\")\n" +
                "      .attr(\"y\", function (d) {\n" +
                "        return icon(d)\n" +
                "          ? parseInt(Math.round(options.nodeRadius * 0.32).toString()) + \"px\"\n" +
                "          : \"4px\";\n" +
                "      })\n" +
                "      .html(function (d) {\n" +
                "        var _icon = icon(d);\n" +
                "        return _icon ? \"&#x\" + _icon : d.id;\n" +
                "      });\n" +
                "  }\n" +
                "  function appendRandomDataToNode(d, maxNodesToGenerate) {\n" +
                "    var data = randomD3Data(d, maxNodesToGenerate);\n" +
                "    updateWithNeo4jData(data);\n" +
                "  }\n" +
                "  function appendRelationship() {\n" +
                "    return relationship\n" +
                "      .enter()\n" +
                "      .append(\"g\")\n" +
                "      .attr(\"class\", \"relationship\")\n" +
                "      .on(\"dblclick\", function (d) {\n" +
                "        if (typeof options.onRelationshipDoubleClick === \"function\") {\n" +
                "          options.onRelationshipDoubleClick(d);\n" +
                "        }\n" +
                "      })\n" +
                "      .on(\"mouseenter\", function (e, d) {\n" +
                "        if (info) {\n" +
                "          updateInfo(d);\n" +
                "        }\n" +
                "        if (typeof options.onRelationshipMouseEnter === \"function\") {\n" +
                "          options.onRelationshipMouseEnter(d);\n" +
                "        }\n" +
                "      })\n" +
                "      .on(\"mouseleave\", function (d) {\n" +
                "        if (info) {\n" +
                "          clearInfo(d);\n" +
                "        }\n" +
                "        if (typeof options.onRelationshipMouseLeave === \"function\") {\n" +
                "          options.onRelationshipMouseLeave(d);\n" +
                "        }\n" +
                "      });\n" +
                "  }\n" +
                "  function appendOutlineToRelationship(r) {\n" +
                "    return r\n" +
                "      .append(\"path\")\n" +
                "      .attr(\"class\", \"outline\")\n" +
                "      .attr(\"fill\", \"#a5abb6\")\n" +
                "      .attr(\"stroke\", \"none\");\n" +
                "  }\n" +
                "  function appendOverlayToRelationship(r) {\n" +
                "    return r.append(\"path\").attr(\"class\", \"overlay\");\n" +
                "  }\n" +
                "  function appendTextToRelationship(r) {\n" +
                "    return r\n" +
                "      .append(\"text\")\n" +
                "      .attr(\"class\", \"text\")\n" +
                "      .attr(\"fill\", \"#000000\")\n" +
                "      .attr(\"font-size\", \"8px\")\n" +
                "      .attr(\"pointer-events\", \"none\")\n" +
                "      .attr(\"text-anchor\", \"middle\")\n" +
                "      .text(function (d) {\n" +
                "        return d.type;\n" +
                "      });\n" +
                "  }\n" +
                "  function appendRelationshipToGraph() {\n" +
                "    var relationship = appendRelationship(),\n" +
                "      text = appendTextToRelationship(relationship),\n" +
                "      outline = appendOutlineToRelationship(relationship),\n" +
                "      overlay = appendOverlayToRelationship(relationship);\n" +
                "    return {\n" +
                "      outline: outline,\n" +
                "      overlay: overlay,\n" +
                "      relationship: relationship,\n" +
                "      text: text\n" +
                "    };\n" +
                "  }\n" +
                "  function class2color(cls) {\n" +
                "    var color = classes2colors[cls];\n" +
                "    if (!color) {\n" +
                "      color = options.colors[numClasses % options.colors.length];\n" +
                "      classes2colors[cls] = color;\n" +
                "      numClasses++;\n" +
                "    }\n" +
                "    return color;\n" +
                "  }\n" +
                "  function class2darkenColor(cls) {\n" +
                "    return d3.rgb(class2color(cls)).darker(1);\n" +
                "  }\n" +
                "  function clearInfo(d) {\n" +
                "    info.html(\"\");\n" +
                "  }\n" +
                "  function color() {\n" +
                "    return options.colors[(options.colors.length * Math.random()) << 0];\n" +
                "  }\n" +
                "  function contains(array, id) {\n" +
                "    var filter = array.filter(function (elem) {\n" +
                "      return elem.id === id;\n" +
                "    });\n" +
                "    return filter.length > 0;\n" +
                "  }\n" +
                "  function defaultColor() {\n" +
                "    return options.relationshipColor;\n" +
                "  }\n" +
                "  function defaultDarkenColor() {\n" +
                "    return d3.rgb(options.colors[options.colors.length - 1]).darker(1);\n" +
                "  }\n" +
                "  function dragEnded(event, d) {\n" +
                "    if (event.active) {\n" +
                "      simulation.alphaTarget(0);\n" +
                "    }\n" +
                "    if (typeof options.onNodeDragEnd === \"function\") {\n" +
                "      options.onNodeDragEnd(d);\n" +
                "    }\n" +
                "  }\n" +
                "  function dragged(event, d) {\n" +
                "    stickNode(event, d);\n" +
                "  }\n" +
                "  function dragStarted(event, d) {\n" +
                "    if (!event.active) {\n" +
                "      simulation.alphaTarget(0.3).restart();\n" +
                "    }\n" +
                "    d.fx = d.x;\n" +
                "    d.fy = d.y;\n" +
                "    if (typeof options.onNodeDragStart === \"function\") {\n" +
                "      options.onNodeDragStart(d);\n" +
                "    }\n" +
                "  }\n" +
                "  function extend(obj1, obj2) {\n" +
                "    var obj = {};\n" +
                "    merge(obj, obj1);\n" +
                "    merge(obj, obj2);\n" +
                "    return obj;\n" +
                "  }\n" +
                "  function icon(d) {\n" +
                "    var code;\n" +
                "    if (options.iconMap && options.showIcons && options.icons) {\n" +
                "      if (\n" +
                "        options.icons[d.labels[0]] &&\n" +
                "        options.iconMap[options.icons[d.labels[0]]]\n" +
                "      ) {\n" +
                "        code = options.iconMap[options.icons[d.labels[0]]];\n" +
                "      } else if (options.iconMap[d.labels[0]]) {\n" +
                "        code = options.iconMap[d.labels[0]];\n" +
                "      } else if (options.icons[d.labels[0]]) {\n" +
                "        code = options.icons[d.labels[0]];\n" +
                "      }\n" +
                "    }\n" +
                "    return code;\n" +
                "  }\n" +
                "  function image(d) {\n" +
                "    var i,\n" +
                "      imagesForLabel,\n" +
                "      img,\n" +
                "      imgLevel,\n" +
                "      label,\n" +
                "      labelPropertyValue,\n" +
                "      property,\n" +
                "      value;\n" +
                "    if (options.images) {\n" +
                "      imagesForLabel = options.imageMap[d.labels[0]];\n" +
                "      if (imagesForLabel) {\n" +
                "        imgLevel = 0;\n" +
                "        for (i = 0; i < imagesForLabel.length; i++) {\n" +
                "          labelPropertyValue = imagesForLabel[i].split(\"|\");\n" +
                "          switch (labelPropertyValue.length) {\n" +
                "            case 3:\n" +
                "              value = labelPropertyValue[2];\n" +
                "            /* falls through */\n" +
                "            case 2:\n" +
                "              property = labelPropertyValue[1];\n" +
                "            /* falls through */\n" +
                "            case 1:\n" +
                "              label = labelPropertyValue[0];\n" +
                "          }\n" +
                "          if (\n" +
                "            d.labels[0] === label &&\n" +
                "            (!property || d.properties[property] !== undefined) &&\n" +
                "            (!value || d.properties[property] === value)\n" +
                "          ) {\n" +
                "            if (labelPropertyValue.length > imgLevel) {\n" +
                "              img = options.images[imagesForLabel[i]];\n" +
                "              imgLevel = labelPropertyValue.length;\n" +
                "            }\n" +
                "          }\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "    return img;\n" +
                "  }\n" +
                "  function createGraph(_selector, _options) {\n" +
                "    initIconMap();\n" +
                "    merge(options, _options);\n" +
                "    if (options.icons) {\n" +
                "      options.showIcons = true;\n" +
                "    }\n" +
                "    if (!options.minCollision) {\n" +
                "      options.minCollision = options.nodeRadius * 2;\n" +
                "    }\n" +
                "    initImageMap();\n" +
                "    selector = _selector;\n" +
                "    container = d3.select(selector);\n" +
                "    container.attr(\"class\", \"neo4jd3\").html(\"\");\n" +
                "    if (options.infoPanel) {\n" +
                "      info = appendInfoPanel(container);\n" +
                "    }\n" +
                "    appendGraph(container);\n" +
                "    simulation = initSimulation();\n" +
                "    if (options.neo4jData) {\n" +
                "      loadNeo4jData();\n" +
                "    } else if (options.neo4jDataUrl) {\n" +
                "      loadNeo4jDataFromUrl(options.neo4jDataUrl);\n" +
                "    } else {\n" +
                "      console.error(\"Error: both neo4jData and neo4jDataUrl are empty!\");\n" +
                "    }\n" +
                "  }\n" +
                "  function initIconMap() {\n" +
                "    Object.keys(options.iconMap).forEach(function (key, index) {\n" +
                "      var keys = key.split(\",\"),\n" +
                "        value = options.iconMap[key];\n" +
                "      keys.forEach(function (key) {\n" +
                "        options.iconMap[key] = value;\n" +
                "      });\n" +
                "    });\n" +
                "  }\n" +
                "  function initImageMap() {\n" +
                "    var key, keys, selector;\n" +
                "    for (key in options.images) {\n" +
                "      if (options.images.hasOwnProperty(key)) {\n" +
                "        keys = key.split(\"|\");\n" +
                "        if (!options.imageMap[keys[0]]) {\n" +
                "          options.imageMap[keys[0]] = [key];\n" +
                "        } else {\n" +
                "          options.imageMap[keys[0]].push(key);\n" +
                "        }\n" +
                "      }\n" +
                "    }\n" +
                "  }\n" +
                "  function initSimulation() {\n" +
                "    var simulation = d3.forceSimulation().velocityDecay(0.8);\n" +
                "    simulation\n" +
                "      //   .force('x', 0.00111)\n" +
                "      //   .force('y', 0.000000001)\n" +
                "      .force(\n" +
                "        \"collide\",\n" +
                "        d3\n" +
                "          .forceCollide()\n" +
                "          .radius(function (d) {\n" +
                "            return options.minCollision;\n" +
                "          })\n" +
                "          .iterations(2)\n" +
                "      )\n" +
                "      .force(\"charge\", d3.forceManyBody())\n" +
                "      .force(\n" +
                "        \"link\",\n" +
                "        d3.forceLink().id(function (d) {\n" +
                "          return d.id;\n" +
                "        })\n" +
                "      )\n" +
                "      .force(\n" +
                "        \"center\",\n" +
                "        d3.forceCenter(\n" +
                "          svg.node().parentElement.parentElement.clientWidth / 2,\n" +
                "          svg.node().parentElement.parentElement.clientHeight / 2\n" +
                "        )\n" +
                "      )\n" +
                "      .on(\"tick\", function () {\n" +
                "        tick();\n" +
                "      })\n" +
                "      .on(\"end\", function () {\n" +
                "        if (options.zoomFit && !justLoaded) {\n" +
                "          justLoaded = true;\n" +
                "          zoomFit(2);\n" +
                "        }\n" +
                "      });\n" +
                "    return simulation;\n" +
                "  }\n" +
                "  function loadNeo4jData() {\n" +
                "    nodes = [];\n" +
                "    relationships = [];\n" +
                "    updateWithNeo4jData(options.neo4jData);\n" +
                "  }\n" +
                "  function loadNeo4jDataFromUrl(neo4jDataUrl) {\n" +
                "    nodes = [];\n" +
                "    relationships = [];\n" +
                "    d3.json(neo4jDataUrl, function (error, data) {\n" +
                "      if (error) {\n" +
                "        throw error;\n" +
                "      }\n" +
                "      updateWithNeo4jData(data);\n" +
                "    });\n" +
                "  }\n" +
                "  function merge(target, source) {\n" +
                "    Object.keys(source).forEach(function (property) {\n" +
                "      target[property] = source[property];\n" +
                "    });\n" +
                "  }\n" +
                "  function neo4jDataToD3Data(data) {\n" +
                "    var graph = {\n" +
                "      nodes: [],\n" +
                "      relationships: []\n" +
                "    };\n" +
                "    data.results.forEach(function (result) {\n" +
                "      result.data.forEach(function (data) {\n" +
                "        data.graph.nodes.forEach(function (node) {\n" +
                "          if (!contains(graph.nodes, node.id)) {\n" +
                "            graph.nodes.push(node);\n" +
                "          }\n" +
                "        });\n" +
                "        data.graph.relationships.forEach(function (relationship) {\n" +
                "          relationship.source = relationship.startNode;\n" +
                "          relationship.target = relationship.endNode;\n" +
                "          graph.relationships.push(relationship);\n" +
                "        });\n" +
                "        data.graph.relationships.sort(function (a, b) {\n" +
                "          if (a.source > b.source) {\n" +
                "            return 1;\n" +
                "          } else if (a.source < b.source) {\n" +
                "            return -1;\n" +
                "          } else {\n" +
                "            if (a.target > b.target) {\n" +
                "              return 1;\n" +
                "            }\n" +
                "            if (a.target < b.target) {\n" +
                "              return -1;\n" +
                "            } else {\n" +
                "              return 0;\n" +
                "            }\n" +
                "          }\n" +
                "        });\n" +
                "        for (var i = 0; i < data.graph.relationships.length; i++) {\n" +
                "          if (\n" +
                "            i !== 0 &&\n" +
                "            data.graph.relationships[i].source ===\n" +
                "              data.graph.relationships[i - 1].source &&\n" +
                "            data.graph.relationships[i].target ===\n" +
                "              data.graph.relationships[i - 1].target\n" +
                "          ) {\n" +
                "            data.graph.relationships[i].linknum =\n" +
                "              data.graph.relationships[i - 1].linknum + 1;\n" +
                "          } else {\n" +
                "            data.graph.relationships[i].linknum = 1;\n" +
                "          }\n" +
                "        }\n" +
                "      });\n" +
                "    });\n" +
                "    return graph;\n" +
                "  }\n" +
                "  function randomD3Data(d, maxNodesToGenerate) {\n" +
                "    var data = {\n" +
                "        nodes: [],\n" +
                "        relationships: []\n" +
                "      },\n" +
                "      i,\n" +
                "      label,\n" +
                "      node,\n" +
                "      numNodes = ((maxNodesToGenerate * Math.random()) << 0) + 1,\n" +
                "      relationship,\n" +
                "      s = size();\n" +
                "    for (i = 0; i < numNodes; i++) {\n" +
                "      label = randomLabel();\n" +
                "      node = {\n" +
                "        id: s.nodes + 1 + i,\n" +
                "        labels: [label],\n" +
                "        properties: {\n" +
                "          random: label\n" +
                "        },\n" +
                "        x: d.x,\n" +
                "        y: d.y\n" +
                "      };\n" +
                "      data.nodes[data.nodes.length] = node;\n" +
                "      relationship = {\n" +
                "        id: s.relationships + 1 + i,\n" +
                "        type: label.toUpperCase(),\n" +
                "        startNode: d.id,\n" +
                "        endNode: s.nodes + 1 + i,\n" +
                "        properties: {\n" +
                "          from: Date.now()\n" +
                "        },\n" +
                "        source: d.id,\n" +
                "        target: s.nodes + 1 + i,\n" +
                "        linknum: s.relationships + 1 + i\n" +
                "      };\n" +
                "      data.relationships[data.relationships.length] = relationship;\n" +
                "    }\n" +
                "    return data;\n" +
                "  }\n" +
                "  function randomLabel() {\n" +
                "    var icons = Object.keys(options.iconMap);\n" +
                "    return icons[(icons.length * Math.random()) << 0];\n" +
                "  }\n" +
                "  function rotate(cx, cy, x, y, angle) {\n" +
                "    var radians = (Math.PI / 180) * angle,\n" +
                "      cos = Math.cos(radians),\n" +
                "      sin = Math.sin(radians),\n" +
                "      nx = cos * (x - cx) + sin * (y - cy) + cx,\n" +
                "      ny = cos * (y - cy) - sin * (x - cx) + cy;\n" +
                "    return { x: nx, y: ny };\n" +
                "  }\n" +
                "  function rotatePoint(c, p, angle) {\n" +
                "    return rotate(c.x, c.y, p.x, p.y, angle);\n" +
                "  }\n" +
                "  function rotation(source, target) {\n" +
                "    return (\n" +
                "      (Math.atan2(target.y - source.y, target.x - source.x) * 180) / Math.PI\n" +
                "    );\n" +
                "  }\n" +
                "  function size() {\n" +
                "    return {\n" +
                "      nodes: nodes.length,\n" +
                "      relationships: relationships.length\n" +
                "    };\n" +
                "  }\n" +
                "  function stickNode(event, d) {\n" +
                "    d.fx = event.x;\n" +
                "    d.fy = event.y;\n" +
                "  }\n" +
                "  function tick() {\n" +
                "    tickNodes();\n" +
                "    tickRelationships();\n" +
                "  }\n" +
                "  function tickNodes() {\n" +
                "    if (node) {\n" +
                "      node.attr(\"transform\", function (d) {\n" +
                "        return \"translate(\" + d.x + \", \" + d.y + \")\";\n" +
                "      });\n" +
                "    }\n" +
                "  }\n" +
                "  function tickRelationships() {\n" +
                "    if (relationship) {\n" +
                "      relationship.attr(\"transform\", function (d) {\n" +
                "        var angle = rotation(d.source, d.target);\n" +
                "        return (\n" +
                "          \"translate(\" +\n" +
                "          d.source.x +\n" +
                "          \", \" +\n" +
                "          d.source.y +\n" +
                "          \") rotate(\" +\n" +
                "          angle +\n" +
                "          \")\"\n" +
                "        );\n" +
                "      });\n" +
                "      tickRelationshipsTexts();\n" +
                "      // tickRelationshipsOutlines();\n" +
                "      tickRelationshipsOverlays();\n" +
                "    }\n" +
                "  }\n" +
                "  function tickRelationshipsOutlines() {\n" +
                "    relationship.each(function (relationship) {\n" +
                "      var rel = d3.select(this),\n" +
                "        outline = rel.select(\".outline\"),\n" +
                "        text = rel.select(\".text\"),\n" +
                "        bbox = text.node().getBBox(),\n" +
                "        padding = 3,\n" +
                "        d = relationship;\n" +
                "      outline.attr(\"d\", function (d) {\n" +
                "        var center = { x: 0, y: 0 },\n" +
                "          angle = rotation(d.source, d.target),\n" +
                "          textBoundingBox = text.node().getBBox(),\n" +
                "          textPadding = 5,\n" +
                "          u = unitaryVector(d.source, d.target),\n" +
                "          textMargin = {\n" +
                "            x:\n" +
                "              (d.target.x -\n" +
                "                d.source.x -\n" +
                "                (textBoundingBox.width + textPadding) * u.x) *\n" +
                "              0.5,\n" +
                "            y:\n" +
                "              (d.target.y -\n" +
                "                d.source.y -\n" +
                "                (textBoundingBox.width + textPadding) * u.y) *\n" +
                "              0.5\n" +
                "          },\n" +
                "          n = unitaryNormalVector(d.source, d.target),\n" +
                "          rotatedPointA1 = rotatePoint(\n" +
                "            center,\n" +
                "            {\n" +
                "              x: 0 + (options.nodeRadius + 1) * u.x - n.x,\n" +
                "              y: 0 + (options.nodeRadius + 1) * u.y - n.y\n" +
                "            },\n" +
                "            angle\n" +
                "          ),\n" +
                "          rotatedPointB1 = rotatePoint(\n" +
                "            center,\n" +
                "            { x: textMargin.x - n.x, y: textMargin.y - n.y },\n" +
                "            angle\n" +
                "          ),\n" +
                "          rotatedPointC1 = rotatePoint(\n" +
                "            center,\n" +
                "            { x: textMargin.x, y: textMargin.y },\n" +
                "            angle\n" +
                "          ),\n" +
                "          rotatedPointD1 = rotatePoint(\n" +
                "            center,\n" +
                "            {\n" +
                "              x: 0 + (options.nodeRadius + 1) * u.x,\n" +
                "              y: 0 + (options.nodeRadius + 1) * u.y\n" +
                "            },\n" +
                "            angle\n" +
                "          ),\n" +
                "          rotatedPointA2 = rotatePoint(\n" +
                "            center,\n" +
                "            {\n" +
                "              x: d.target.x - d.source.x - textMargin.x - n.x,\n" +
                "              y: d.target.y - d.source.y - textMargin.y - n.y\n" +
                "            },\n" +
                "            angle\n" +
                "          ),\n" +
                "          rotatedPointB2 = rotatePoint(\n" +
                "            center,\n" +
                "            {\n" +
                "              x:\n" +
                "                d.target.x -\n" +
                "                d.source.x -\n" +
                "                (options.nodeRadius + 1) * u.x -\n" +
                "                n.x -\n" +
                "                u.x * options.arrowSize,\n" +
                "              y:\n" +
                "                d.target.y -\n" +
                "                d.source.y -\n" +
                "                (options.nodeRadius + 1) * u.y -\n" +
                "                n.y -\n" +
                "                u.y * options.arrowSize\n" +
                "            },\n" +
                "            angle\n" +
                "          ),\n" +
                "          rotatedPointC2 = rotatePoint(\n" +
                "            center,\n" +
                "            {\n" +
                "              x:\n" +
                "                d.target.x -\n" +
                "                d.source.x -\n" +
                "                (options.nodeRadius + 1) * u.x -\n" +
                "                n.x +\n" +
                "                (n.x - u.x) * options.arrowSize,\n" +
                "              y:\n" +
                "                d.target.y -\n" +
                "                d.source.y -\n" +
                "                (options.nodeRadius + 1) * u.y -\n" +
                "                n.y +\n" +
                "                (n.y - u.y) * options.arrowSize\n" +
                "            },\n" +
                "            angle\n" +
                "          ),\n" +
                "          rotatedPointD2 = rotatePoint(\n" +
                "            center,\n" +
                "            {\n" +
                "              x: d.target.x - d.source.x - (options.nodeRadius + 1) * u.x,\n" +
                "              y: d.target.y - d.source.y - (options.nodeRadius + 1) * u.y\n" +
                "            },\n" +
                "            angle\n" +
                "          ),\n" +
                "          rotatedPointE2 = rotatePoint(\n" +
                "            center,\n" +
                "            {\n" +
                "              x:\n" +
                "                d.target.x -\n" +
                "                d.source.x -\n" +
                "                (options.nodeRadius + 1) * u.x +\n" +
                "                (-n.x - u.x) * options.arrowSize,\n" +
                "              y:\n" +
                "                d.target.y -\n" +
                "                d.source.y -\n" +
                "                (options.nodeRadius + 1) * u.y +\n" +
                "                (-n.y - u.y) * options.arrowSize\n" +
                "            },\n" +
                "            angle\n" +
                "          ),\n" +
                "          rotatedPointF2 = rotatePoint(\n" +
                "            center,\n" +
                "            {\n" +
                "              x:\n" +
                "                d.target.x -\n" +
                "                d.source.x -\n" +
                "                (options.nodeRadius + 1) * u.x -\n" +
                "                u.x * options.arrowSize,\n" +
                "              y:\n" +
                "                d.target.y -\n" +
                "                d.source.y -\n" +
                "                (options.nodeRadius + 1) * u.y -\n" +
                "                u.y * options.arrowSize\n" +
                "            },\n" +
                "            angle\n" +
                "          ),\n" +
                "          rotatedPointG2 = rotatePoint(\n" +
                "            center,\n" +
                "            {\n" +
                "              x: d.target.x - d.source.x - textMargin.x,\n" +
                "              y: d.target.y - d.source.y - textMargin.y\n" +
                "            },\n" +
                "            angle\n" +
                "          );\n" +
                "\n" +
                "        return (\n" +
                "          \"M \" +\n" +
                "          rotatedPointA1.x +\n" +
                "          \" \" +\n" +
                "          rotatedPointA1.y +\n" +
                "          \" L \" +\n" +
                "          rotatedPointB1.x +\n" +
                "          \" \" +\n" +
                "          rotatedPointB1.y +\n" +
                "          \" L \" +\n" +
                "          rotatedPointC1.x +\n" +
                "          \" \" +\n" +
                "          rotatedPointC1.y +\n" +
                "          \" L \" +\n" +
                "          rotatedPointD1.x +\n" +
                "          \" \" +\n" +
                "          rotatedPointD1.y +\n" +
                "          \" Z M \" +\n" +
                "          rotatedPointA2.x +\n" +
                "          \" \" +\n" +
                "          rotatedPointA2.y +\n" +
                "          \" L \" +\n" +
                "          rotatedPointB2.x +\n" +
                "          \" \" +\n" +
                "          rotatedPointB2.y +\n" +
                "          \" L \" +\n" +
                "          rotatedPointC2.x +\n" +
                "          \" \" +\n" +
                "          rotatedPointC2.y +\n" +
                "          \" L \" +\n" +
                "          rotatedPointD2.x +\n" +
                "          \" \" +\n" +
                "          rotatedPointD2.y +\n" +
                "          \" L \" +\n" +
                "          rotatedPointE2.x +\n" +
                "          \" \" +\n" +
                "          rotatedPointE2.y +\n" +
                "          \" L \" +\n" +
                "          rotatedPointF2.x +\n" +
                "          \" \" +\n" +
                "          rotatedPointF2.y +\n" +
                "          \" L \" +\n" +
                "          rotatedPointG2.x +\n" +
                "          \" \" +\n" +
                "          rotatedPointG2.y +\n" +
                "          \" Z\"\n" +
                "        );\n" +
                "      });\n" +
                "    });\n" +
                "  }\n" +
                "  function tickRelationshipsOverlays() {\n" +
                "    relationshipOverlay.attr(\"d\", function (d) {\n" +
                "      if (d.source == d.target) {\n" +
                "        return \"M 0 0 L 0 0 L 0 0 L 0 0 Z\";\n" +
                "      }\n" +
                "      var center = { x: 0, y: 0 },\n" +
                "        angle = rotation(d.source, d.target),\n" +
                "        n1 = unitaryNormalVector(d.source, d.target),\n" +
                "        n = unitaryNormalVector(d.source, d.target, 50),\n" +
                "        rotatedPointA = rotatePoint(center, { x: 0 - n.x, y: 0 - n.y }, angle),\n" +
                "        rotatedPointB = rotatePoint(\n" +
                "          center,\n" +
                "          {\n" +
                "            x: d.target.x - d.source.x - n.x,\n" +
                "            y: d.target.y - d.source.y - n.y\n" +
                "          },\n" +
                "          angle\n" +
                "        ),\n" +
                "        rotatedPointC = rotatePoint(\n" +
                "          center,\n" +
                "          {\n" +
                "            x: d.target.x - d.source.x + n.x - n1.x,\n" +
                "            y: d.target.y - d.source.y + n.y - n1.y\n" +
                "          },\n" +
                "          angle\n" +
                "        ),\n" +
                "        rotatedPointD = rotatePoint(\n" +
                "          center,\n" +
                "          { x: 0 + n.x - n1.x, y: 0 + n.y - n1.y },\n" +
                "          angle\n" +
                "        );\n" +
                "      // console.log(\n" +
                "      //     \"结果\",\n" +
                "      //     d.source == d.target,\n" +
                "      //     d.source,\n" +
                "      //     d.target,\n" +
                "      //     \"M \" +\n" +
                "      //     rotatedPointA.x +\n" +
                "      //     \" \" +\n" +
                "      //     rotatedPointA.y +\n" +
                "      //     \" L \" +\n" +
                "      //     rotatedPointB.x +\n" +
                "      //     \" \" +\n" +
                "      //     rotatedPointB.y +\n" +
                "      //     \" L \" +\n" +
                "      //     rotatedPointC.x +\n" +
                "      //     \" \" +\n" +
                "      //     rotatedPointC.y +\n" +
                "      //     \" L \" +\n" +
                "      //     rotatedPointD.x +\n" +
                "      //     \" \" +\n" +
                "      //     rotatedPointD.y +\n" +
                "      //     \" Z\"\n" +
                "      // );\n" +
                "      return (\n" +
                "        \"M \" +\n" +
                "        rotatedPointA.x +\n" +
                "        \" \" +\n" +
                "        rotatedPointA.y +\n" +
                "        \" L \" +\n" +
                "        rotatedPointB.x +\n" +
                "        \" \" +\n" +
                "        rotatedPointB.y +\n" +
                "        \" L \" +\n" +
                "        rotatedPointC.x +\n" +
                "        \" \" +\n" +
                "        rotatedPointC.y +\n" +
                "        \" L \" +\n" +
                "        rotatedPointD.x +\n" +
                "        \" \" +\n" +
                "        rotatedPointD.y +\n" +
                "        \" Z\"\n" +
                "      );\n" +
                "    });\n" +
                "  }\n" +
                "  function tickRelationshipsTexts() {\n" +
                "    relationshipText.attr(\"transform\", function (d) {\n" +
                "      if (d.source == d.target) {\n" +
                "        return \"translate(0, 0) rotate(0)\";\n" +
                "      }\n" +
                "      var angle = (rotation(d.source, d.target) + 360) % 360,\n" +
                "        mirror = angle > 90 && angle < 270,\n" +
                "        center = { x: 0, y: 0 },\n" +
                "        n = unitaryNormalVector(d.source, d.target),\n" +
                "        nWeight = mirror ? 2 : -3,\n" +
                "        point = {\n" +
                "          x: (d.target.x - d.source.x) * 0.5 + n.x * nWeight,\n" +
                "          y: (d.target.y - d.source.y) * 0.5 + n.y * nWeight\n" +
                "        },\n" +
                "        rotatedPoint = rotatePoint(center, point, angle);\n" +
                "      // console.log(\n" +
                "      //     \"结果\",d.source, d.target,\n" +
                "      //     \"translate(\" +\n" +
                "      //     rotatedPoint.x +\n" +
                "      //     \", \" +\n" +
                "      //     rotatedPoint.y +\n" +
                "      //     \") rotate(\" +\n" +
                "      //     (mirror ? 180 : 0) +\n" +
                "      //     \")\"\n" +
                "      // );\n" +
                "      return (\n" +
                "        \"translate(\" +\n" +
                "        rotatedPoint.x +\n" +
                "        \", \" +\n" +
                "        rotatedPoint.y +\n" +
                "        \") rotate(\" +\n" +
                "        (mirror ? 180 : 0) +\n" +
                "        \")\"\n" +
                "      );\n" +
                "    });\n" +
                "  }\n" +
                "  function toString(d) {\n" +
                "    var s = d.labels ? d.labels[0] : d.type;\n" +
                "    s += \" (<id>: \" + d.id;\n" +
                "    Object.keys(d.properties).forEach(function (property) {\n" +
                "      s += \", \" + property + \": \" + JSON.stringify(d.properties[property]);\n" +
                "    });\n" +
                "    s += \")\";\n" +
                "    return s;\n" +
                "  }\n" +
                "  function unitaryNormalVector(source, target, newLength) {\n" +
                "    var center = { x: 0, y: 0 };\n" +
                "    var vector = unitaryVector(source, target, newLength);\n" +
                "    return rotatePoint(center, vector, 90);\n" +
                "  }\n" +
                "  function unitaryVector(source, target, newLength) {\n" +
                "    var length =\n" +
                "      Math.sqrt(\n" +
                "        Math.pow(target.x - source.x, 2) + Math.pow(target.y - source.y, 2)\n" +
                "      ) / Math.sqrt(newLength || 1);\n" +
                "    return {\n" +
                "      x: (target.x - source.x) / length,\n" +
                "      y: (target.y - source.y) / length\n" +
                "    };\n" +
                "  }\n" +
                "  function updateWithD3Data(d3Data) {\n" +
                "    updateNodesAndRelationships(d3Data.nodes, d3Data.relationships);\n" +
                "  }\n" +
                "  function updateWithNeo4jData(neo4jData) {\n" +
                "    var d3Data = neo4jDataToD3Data(neo4jData);\n" +
                "    updateWithD3Data(d3Data);\n" +
                "  }\n" +
                "  function updateInfo(d) {\n" +
                "    clearInfo();\n" +
                "    if (d.labels) {\n" +
                "      appendInfoElementClass(\"class\", d.labels[0]);\n" +
                "    } else {\n" +
                "      appendInfoElementRelationship(\"class\", d.type);\n" +
                "    }\n" +
                "    appendInfoElementProperty(\"property\", \"id\", d.id);\n" +
                "    Object.keys(d.properties).forEach(function (property) {\n" +
                "      appendInfoElementProperty(\"property\", property, d.properties[property]);\n" +
                "    });\n" +
                "  }\n" +
                "  function updateNodes(n) {\n" +
                "    Array.prototype.push.apply(nodes, n);\n" +
                "    node = svgNodes.selectAll(\".node\").data(nodes, function (d) {\n" +
                "      return d.id;\n" +
                "    });\n" +
                "    var nodeEnter = appendNodeToGraph();\n" +
                "    node = nodeEnter.merge(node);\n" +
                "  }\n" +
                "  function updateNodesAndRelationships(n, r) {\n" +
                "    updateRelationships(r);\n" +
                "    updateNodes(n);\n" +
                "    simulation.nodes(nodes);\n" +
                "    simulation.force(\"link\").links(relationships);\n" +
                "  }\n" +
                "  function updateRelationships(r) {\n" +
                "    Array.prototype.push.apply(relationships, r);\n" +
                "    relationship = svgRelationships\n" +
                "      .selectAll(\".relationship\")\n" +
                "      .data(relationships, function (d) {\n" +
                "        return d.id;\n" +
                "      });\n" +
                "    var relationshipEnter = appendRelationshipToGraph();\n" +
                "    relationship = relationshipEnter.relationship.merge(relationship);\n" +
                "    relationshipOutline = svg.selectAll(\".relationship .outline\");\n" +
                "    relationshipOutline = relationshipEnter.outline.merge(relationshipOutline);\n" +
                "    relationshipOverlay = svg.selectAll(\".relationship .overlay\");\n" +
                "    relationshipOverlay = relationshipEnter.overlay.merge(relationshipOverlay);\n" +
                "    relationshipText = svg.selectAll(\".relationship .text\");\n" +
                "    relationshipText = relationshipEnter.text.merge(relationshipText);\n" +
                "  }\n" +
                "  function version() {\n" +
                "    return VERSION;\n" +
                "  }\n" +
                "  function zoomFit(transitionDuration) {\n" +
                "    var bounds = svg.node().getBBox(),\n" +
                "      parent = svg.node().parentElement.parentElement,\n" +
                "      fullWidth = parent && parent.clientWidth ? parent.clientWidth : \"100vw\",\n" +
                "      fullHeight =\n" +
                "        parent && parent.clientHeight ? parent.clientHeight : \"100vh\",\n" +
                "      width = bounds.width,\n" +
                "      height = bounds.height,\n" +
                "      midX = bounds.x + width / 2,\n" +
                "      midY = bounds.y + height / 2;\n" +
                "    if (width === 0 || height === 0) {\n" +
                "      return;\n" +
                "    }\n" +
                "    svgScale = 0.85 / Math.max(width / fullWidth, height / fullHeight);\n" +
                "    svgTranslate = [\n" +
                "      fullWidth / 2 - svgScale * midX,\n" +
                "      fullHeight / 2 - svgScale * midY\n" +
                "    ];\n" +
                "    svg.attr(\n" +
                "      \"transform\",\n" +
                "      \"translate(\" +\n" +
                "        svgTranslate[0] +\n" +
                "        \", \" +\n" +
                "        svgTranslate[1] +\n" +
                "        \") scale(\" +\n" +
                "        svgScale +\n" +
                "        \")\"\n" +
                "    );\n" +
                "  }\n" +
                "  return {\n" +
                "    appendRandomDataToNode: appendRandomDataToNode,\n" +
                "    neo4jDataToD3Data: neo4jDataToD3Data,\n" +
                "    randomD3Data: randomD3Data,\n" +
                "    size: size,\n" +
                "    updateWithD3Data: updateWithD3Data,\n" +
                "    updateWithNeo4jData: updateWithNeo4jData,\n" +
                "    version: version,\n" +
                "    createGraph: createGraph\n" +
                "  };\n" +
                "}\n" +
                "export default Neo4jD3();\n", "\"use strict\";\n" +
                "Object.defineProperty(exports, \"__esModule\", { value: true });\n" +
                "// @ts-ignore\n" +
                "var d3 = require(\"d3\");\n" +
                "require(\"./styles/styles.css\");\n" +
                "require(\"font-awesome/css/font-awesome.css\");\n" +
                "var interface_1 = require(\"./interfaces/interface\");\n" +
                "function Neo4jD3() {\n" +
                "    var container, info, node, nodes, relationship, relationshipOutline, relationshipOverlay, relationshipText, relationships, selector, simulation, svg, svgNodes, svgRelationships, svgScale, svgTranslate, classes2colors = {}, justLoaded = false, numClasses = 0, options = {\n" +
                "        arrowSize: 4,\n" +
                "        colors: interface_1.colors,\n" +
                "        highlight: undefined,\n" +
                "        iconMap: interface_1.fontAwesomeIcons,\n" +
                "        icons: undefined,\n" +
                "        imageMap: {},\n" +
                "        images: undefined,\n" +
                "        infoPanel: true,\n" +
                "        minCollision: undefined,\n" +
                "        neo4jData: undefined,\n" +
                "        neo4jDataUrl: undefined,\n" +
                "        nodeOutlineFillColor: undefined,\n" +
                "        nodeRadius: 25,\n" +
                "        relationshipColor: 'red',\n" +
                "        zoomFit: false,\n" +
                "    }, VERSION = '1.0.1';\n" +
                "    function appendGraph(container) {\n" +
                "        svg = container\n" +
                "            .append('svg')\n" +
                "            .attr('width', '100%')\n" +
                "            .attr('height', '100%')\n" +
                "            .attr('class', 'neo4jd3-graph')\n" +
                "            .call(d3.zoom().on('zoom', function () {\n" +
                "            var scale = d3.event.transform.k, translate = [d3.event.transform.x, d3.event.transform.y];\n" +
                "            if (svgTranslate) {\n" +
                "                translate[0] += svgTranslate[0];\n" +
                "                translate[1] += svgTranslate[1];\n" +
                "            }\n" +
                "            if (svgScale) {\n" +
                "                scale *= svgScale;\n" +
                "            }\n" +
                "            svg.attr('transform', 'translate(' + translate[0] + ', ' + translate[1] + ') scale(' + scale + ')');\n" +
                "        }))\n" +
                "            .on('dblclick.zoom', null)\n" +
                "            .append('g')\n" +
                "            .attr('width', '100%')\n" +
                "            .attr('height', '100%');\n" +
                "        svgRelationships = svg.append('g').attr('class', 'relationships');\n" +
                "        svgNodes = svg.append('g').attr('class', 'nodes');\n" +
                "    }\n" +
                "    function appendImageToNode(node) {\n" +
                "        return node\n" +
                "            .append('image')\n" +
                "            .attr('height', function (d) {\n" +
                "            return icon(d) ? '24px' : '30px';\n" +
                "        })\n" +
                "            .attr('x', function (d) {\n" +
                "            return icon(d) ? '5px' : '-15px';\n" +
                "        })\n" +
                "            .attr('xlink:href', function (d) {\n" +
                "            return image(d);\n" +
                "        })\n" +
                "            .attr('y', function (d) {\n" +
                "            return icon(d) ? '5px' : '-16px';\n" +
                "        })\n" +
                "            .attr('width', function (d) {\n" +
                "            return icon(d) ? '24px' : '30px';\n" +
                "        });\n" +
                "    }\n" +
                "    function appendInfoPanel(container) {\n" +
                "        return container.append('div').attr('class', 'neo4jd3-info');\n" +
                "    }\n" +
                "    function appendInfoElement(cls, isNode, property, value) {\n" +
                "        var table = info.append('table').style('border-collapse', 'collapse').style('width', '100%');\n" +
                "        var row = table.append('tr');\n" +
                "        if (!value) {\n" +
                "            row\n" +
                "                .append('td')\n" +
                "                .attr('class', cls)\n" +
                "                .style('border', '1px solid #dddddd')\n" +
                "                .style('padding', '8px')\n" +
                "                .style('width', '200px')\n" +
                "                .style('text-wrap', 'no-wrap')\n" +
                "                .html('<strong>Name</strong>');\n" +
                "            row\n" +
                "                .append('td')\n" +
                "                .style('border', '1px solid #dddddd')\n" +
                "                .style('padding', '8px')\n" +
                "                .style('width', 'auto')\n" +
                "                .style('text-wrap', 'no-wrap')\n" +
                "                .html('<strong>' + property + '</strong>');\n" +
                "            row\n" +
                "                .style('background-color', function (d) {\n" +
                "                return options.nodeOutlineFillColor\n" +
                "                    ? options.nodeOutlineFillColor\n" +
                "                    : isNode\n" +
                "                        ? class2color(property)\n" +
                "                        : defaultColor();\n" +
                "            })\n" +
                "                .style('border-color', function (d) {\n" +
                "                return options.nodeOutlineFillColor\n" +
                "                    ? class2darkenColor(options.nodeOutlineFillColor)\n" +
                "                    : isNode\n" +
                "                        ? class2darkenColor(property)\n" +
                "                        : defaultDarkenColor();\n" +
                "            })\n" +
                "                .style('color', function (d) {\n" +
                "                return options.nodeOutlineFillColor ? class2darkenColor(options.nodeOutlineFillColor) : '#fff';\n" +
                "            });\n" +
                "        }\n" +
                "        else {\n" +
                "            row\n" +
                "                .append('td')\n" +
                "                .attr('class', cls)\n" +
                "                .style('border', '1px solid #dddddd')\n" +
                "                .style('padding', '8px')\n" +
                "                .style('width', '200px')\n" +
                "                .style('text-wrap', 'no-wrap')\n" +
                "                .html('<strong>' + property + '</strong>');\n" +
                "            row\n" +
                "                .append('td')\n" +
                "                .style('border', '1px solid #dddddd')\n" +
                "                .style('padding', '8px')\n" +
                "                .style('width', 'auto')\n" +
                "                .style('text-wrap', 'no-wrap')\n" +
                "                .html('<strong>' + value + '</strong>');\n" +
                "        }\n" +
                "    }\n" +
                "    function appendInfoElementClass(cls, node) {\n" +
                "        appendInfoElement(cls, true, node);\n" +
                "    }\n" +
                "    function appendInfoElementProperty(cls, property, value) {\n" +
                "        appendInfoElement(cls, false, property, value);\n" +
                "    }\n" +
                "    function appendInfoElementRelationship(cls, relationship) {\n" +
                "        appendInfoElement(cls, false, relationship);\n" +
                "    }\n" +
                "    function appendNode() {\n" +
                "        return node\n" +
                "            .enter()\n" +
                "            .append('g')\n" +
                "            .attr('class', function (d) {\n" +
                "            var highlight, i, classes = 'node', label = d.labels[0];\n" +
                "            if (icon(d)) {\n" +
                "                classes += ' node-icon';\n" +
                "            }\n" +
                "            if (image(d)) {\n" +
                "                classes += ' node-image';\n" +
                "            }\n" +
                "            if (options.highlight) {\n" +
                "                for (i = 0; i < options.highlight.length; i++) {\n" +
                "                    highlight = options.highlight[i];\n" +
                "                    if (d.labels[0] === highlight.class && d.properties[highlight.property] === highlight.value) {\n" +
                "                        classes += ' node-highlighted';\n" +
                "                        break;\n" +
                "                    }\n" +
                "                }\n" +
                "            }\n" +
                "            return classes;\n" +
                "        })\n" +
                "            .on('click', function (d) {\n" +
                "            d.fx = d.fy = null;\n" +
                "            if (typeof options.onNodeClick === 'function') {\n" +
                "                options.onNodeClick(d);\n" +
                "            }\n" +
                "        })\n" +
                "            .on('dblclick', function (d) {\n" +
                "            stickNode(d);\n" +
                "            if (typeof options.onNodeDoubleClick === 'function') {\n" +
                "                options.onNodeDoubleClick(d);\n" +
                "            }\n" +
                "        })\n" +
                "            .on('mouseenter', function (d) {\n" +
                "            if (info) {\n" +
                "                updateInfo(d);\n" +
                "            }\n" +
                "            if (typeof options.onNodeMouseEnter === 'function') {\n" +
                "                options.onNodeMouseEnter(d);\n" +
                "            }\n" +
                "        })\n" +
                "            .on('mouseleave', function (d) {\n" +
                "            if (info) {\n" +
                "                clearInfo(d);\n" +
                "            }\n" +
                "            if (typeof options.onNodeMouseLeave === 'function') {\n" +
                "                options.onNodeMouseLeave(d);\n" +
                "            }\n" +
                "        })\n" +
                "            .call(d3.drag().on('start', dragStarted).on('drag', dragged).on('end', dragEnded));\n" +
                "    }\n" +
                "    function appendNodeToGraph() {\n" +
                "        var n = appendNode();\n" +
                "        appendRingToNode(n);\n" +
                "        // appendOutlineToNode(n);\n" +
                "        if (options.icons) {\n" +
                "            appendTextToNode(n);\n" +
                "        }\n" +
                "        if (options.images) {\n" +
                "            appendImageToNode(n);\n" +
                "        }\n" +
                "        return n;\n" +
                "    }\n" +
                "    function appendOutlineToNode(node) {\n" +
                "        return node\n" +
                "            .append('circle')\n" +
                "            // .attr('class', 'outline')\n" +
                "            .attr('r', options.nodeRadius)\n" +
                "            .style('fill', function (d) {\n" +
                "            return options.nodeOutlineFillColor ? options.nodeOutlineFillColor : class2color(d.labels[0]);\n" +
                "        })\n" +
                "            .style('stroke', function (d) {\n" +
                "            return options.nodeOutlineFillColor\n" +
                "                ? class2darkenColor(options.nodeOutlineFillColor)\n" +
                "                : class2darkenColor(d.labels[0]);\n" +
                "        })\n" +
                "            .append('title')\n" +
                "            .text(function (d) {\n" +
                "            return toString(d);\n" +
                "        });\n" +
                "    }\n" +
                "    function appendRingToNode(node) {\n" +
                "        return node\n" +
                "            .append('circle')\n" +
                "            .attr('class', 'ring')\n" +
                "            .attr('r', options.nodeRadius * 1.16)\n" +
                "            .append('title')\n" +
                "            .text(function (d) {\n" +
                "            return toString(d);\n" +
                "        });\n" +
                "    }\n" +
                "    function appendTextToNode(node) {\n" +
                "        return node\n" +
                "            .append('text')\n" +
                "            .attr('class', function (d) {\n" +
                "            return 'text' + (icon(d) ? ' icon' : '');\n" +
                "        })\n" +
                "            .attr('fill', '#ffffff')\n" +
                "            .attr('font-size', function (d) {\n" +
                "            return icon(d) ? options.nodeRadius + 'px' : '10px';\n" +
                "        })\n" +
                "            .attr('pointer-events', 'none')\n" +
                "            .attr('text-anchor', 'middle')\n" +
                "            .attr('y', function (d) {\n" +
                "            return icon(d) ? parseInt(Math.round(options.nodeRadius * 0.32).toString()) + 'px' : '4px';\n" +
                "        })\n" +
                "            .html(function (d) {\n" +
                "            var _icon = icon(d);\n" +
                "            return _icon ? '&#x' + _icon : d.id;\n" +
                "        });\n" +
                "    }\n" +
                "    function appendRandomDataToNode(d, maxNodesToGenerate) {\n" +
                "        var data = randomD3Data(d, maxNodesToGenerate);\n" +
                "        updateWithNeo4jData(data);\n" +
                "    }\n" +
                "    function appendRelationship() {\n" +
                "        return relationship\n" +
                "            .enter()\n" +
                "            .append('g')\n" +
                "            .attr('class', 'relationship')\n" +
                "            .on('dblclick', function (d) {\n" +
                "            if (typeof options.onRelationshipDoubleClick === 'function') {\n" +
                "                options.onRelationshipDoubleClick(d);\n" +
                "            }\n" +
                "        })\n" +
                "            .on('mouseenter', function (d) {\n" +
                "            if (info) {\n" +
                "                updateInfo(d);\n" +
                "            }\n" +
                "            if (typeof options.onRelationshipMouseEnter === 'function') {\n" +
                "                options.onRelationshipMouseEnter(d);\n" +
                "            }\n" +
                "        })\n" +
                "            .on('mouseleave', function (d) {\n" +
                "            if (info) {\n" +
                "                clearInfo(d);\n" +
                "            }\n" +
                "            if (typeof options.onRelationshipMouseLeave === 'function') {\n" +
                "                options.onRelationshipMouseLeave(d);\n" +
                "            }\n" +
                "        });\n" +
                "    }\n" +
                "    function appendOutlineToRelationship(r) {\n" +
                "        return r.append('path').attr('class', 'outline').attr('fill', '#a5abb6').attr('stroke', 'none');\n" +
                "    }\n" +
                "    function appendOverlayToRelationship(r) {\n" +
                "        return r.append('path').attr('class', 'overlay');\n" +
                "    }\n" +
                "    function appendTextToRelationship(r) {\n" +
                "        return r\n" +
                "            .append('text')\n" +
                "            .attr('class', 'text')\n" +
                "            .attr('fill', '#000000')\n" +
                "            .attr('font-size', '8px')\n" +
                "            .attr('pointer-events', 'none')\n" +
                "            .attr('text-anchor', 'middle')\n" +
                "            .text(function (d) {\n" +
                "            return d.type;\n" +
                "        });\n" +
                "    }\n" +
                "    function appendRelationshipToGraph() {\n" +
                "        var relationship = appendRelationship(), text = appendTextToRelationship(relationship), outline = appendOutlineToRelationship(relationship), overlay = appendOverlayToRelationship(relationship);\n" +
                "        return {\n" +
                "            outline: outline,\n" +
                "            overlay: overlay,\n" +
                "            relationship: relationship,\n" +
                "            text: text,\n" +
                "        };\n" +
                "    }\n" +
                "    function class2color(cls) {\n" +
                "        var color = classes2colors[cls];\n" +
                "        if (!color) {\n" +
                "            color = options.colors[numClasses % options.colors.length];\n" +
                "            classes2colors[cls] = color;\n" +
                "            numClasses++;\n" +
                "        }\n" +
                "        return color;\n" +
                "    }\n" +
                "    function class2darkenColor(cls) {\n" +
                "        return d3.rgb(class2color(cls)).darker(1);\n" +
                "    }\n" +
                "    function clearInfo(d) {\n" +
                "        info.html('');\n" +
                "    }\n" +
                "    function color() {\n" +
                "        return options.colors[(options.colors.length * Math.random()) << 0];\n" +
                "    }\n" +
                "    function contains(array, id) {\n" +
                "        var filter = array.filter(function (elem) {\n" +
                "            return elem.id === id;\n" +
                "        });\n" +
                "        return filter.length > 0;\n" +
                "    }\n" +
                "    function defaultColor() {\n" +
                "        return options.relationshipColor;\n" +
                "    }\n" +
                "    function defaultDarkenColor() {\n" +
                "        return d3.rgb(options.colors[options.colors.length - 1]).darker(1);\n" +
                "    }\n" +
                "    function dragEnded(d) {\n" +
                "        if (!d3.event.active) {\n" +
                "            simulation.alphaTarget(0);\n" +
                "        }\n" +
                "        if (typeof options.onNodeDragEnd === 'function') {\n" +
                "            options.onNodeDragEnd(d);\n" +
                "        }\n" +
                "    }\n" +
                "    function dragged(d) {\n" +
                "        stickNode(d);\n" +
                "    }\n" +
                "    function dragStarted(d) {\n" +
                "        if (!d3.event.active) {\n" +
                "            simulation.alphaTarget(0.3).restart();\n" +
                "        }\n" +
                "        d.fx = d.x;\n" +
                "        d.fy = d.y;\n" +
                "        if (typeof options.onNodeDragStart === 'function') {\n" +
                "            options.onNodeDragStart(d);\n" +
                "        }\n" +
                "    }\n" +
                "    function extend(obj1, obj2) {\n" +
                "        var obj = {};\n" +
                "        merge(obj, obj1);\n" +
                "        merge(obj, obj2);\n" +
                "        return obj;\n" +
                "    }\n" +
                "    function icon(d) {\n" +
                "        var code;\n" +
                "        if (options.iconMap && options.showIcons && options.icons) {\n" +
                "            if (options.icons[d.labels[0]] && options.iconMap[options.icons[d.labels[0]]]) {\n" +
                "                code = options.iconMap[options.icons[d.labels[0]]];\n" +
                "            }\n" +
                "            else if (options.iconMap[d.labels[0]]) {\n" +
                "                code = options.iconMap[d.labels[0]];\n" +
                "            }\n" +
                "            else if (options.icons[d.labels[0]]) {\n" +
                "                code = options.icons[d.labels[0]];\n" +
                "            }\n" +
                "        }\n" +
                "        return code;\n" +
                "    }\n" +
                "    function image(d) {\n" +
                "        var i, imagesForLabel, img, imgLevel, label, labelPropertyValue, property, value;\n" +
                "        if (options.images) {\n" +
                "            imagesForLabel = options.imageMap[d.labels[0]];\n" +
                "            if (imagesForLabel) {\n" +
                "                imgLevel = 0;\n" +
                "                for (i = 0; i < imagesForLabel.length; i++) {\n" +
                "                    labelPropertyValue = imagesForLabel[i].split('|');\n" +
                "                    switch (labelPropertyValue.length) {\n" +
                "                        case 3:\n" +
                "                            value = labelPropertyValue[2];\n" +
                "                        /* falls through */\n" +
                "                        case 2:\n" +
                "                            property = labelPropertyValue[1];\n" +
                "                        /* falls through */\n" +
                "                        case 1:\n" +
                "                            label = labelPropertyValue[0];\n" +
                "                    }\n" +
                "                    if (d.labels[0] === label &&\n" +
                "                        (!property || d.properties[property] !== undefined) &&\n" +
                "                        (!value || d.properties[property] === value)) {\n" +
                "                        if (labelPropertyValue.length > imgLevel) {\n" +
                "                            img = options.images[imagesForLabel[i]];\n" +
                "                            imgLevel = labelPropertyValue.length;\n" +
                "                        }\n" +
                "                    }\n" +
                "                }\n" +
                "            }\n" +
                "        }\n" +
                "        return img;\n" +
                "    }\n" +
                "    function createGraph(_selector, _options) {\n" +
                "        initIconMap();\n" +
                "        merge(options, _options);\n" +
                "        if (options.icons) {\n" +
                "            options.showIcons = true;\n" +
                "        }\n" +
                "        if (!options.minCollision) {\n" +
                "            options.minCollision = options.nodeRadius * 2;\n" +
                "        }\n" +
                "        initImageMap();\n" +
                "        selector = _selector;\n" +
                "        container = d3.select(selector);\n" +
                "        container.attr('class', 'neo4jd3').html('');\n" +
                "        if (options.infoPanel) {\n" +
                "            info = appendInfoPanel(container);\n" +
                "        }\n" +
                "        appendGraph(container);\n" +
                "        simulation = initSimulation();\n" +
                "        if (options.neo4jData) {\n" +
                "            loadNeo4jData();\n" +
                "        }\n" +
                "        else if (options.neo4jDataUrl) {\n" +
                "            loadNeo4jDataFromUrl(options.neo4jDataUrl);\n" +
                "        }\n" +
                "        else {\n" +
                "            console.error('Error: both neo4jData and neo4jDataUrl are empty!');\n" +
                "        }\n" +
                "    }\n" +
                "    function initIconMap() {\n" +
                "        Object.keys(options.iconMap).forEach(function (key, index) {\n" +
                "            var keys = key.split(','), value = options.iconMap[key];\n" +
                "            keys.forEach(function (key) {\n" +
                "                options.iconMap[key] = value;\n" +
                "            });\n" +
                "        });\n" +
                "    }\n" +
                "    function initImageMap() {\n" +
                "        var key, keys, selector;\n" +
                "        for (key in options.images) {\n" +
                "            if (options.images.hasOwnProperty(key)) {\n" +
                "                keys = key.split('|');\n" +
                "                if (!options.imageMap[keys[0]]) {\n" +
                "                    options.imageMap[keys[0]] = [key];\n" +
                "                }\n" +
                "                else {\n" +
                "                    options.imageMap[keys[0]].push(key);\n" +
                "                }\n" +
                "            }\n" +
                "        }\n" +
                "    }\n" +
                "    function initSimulation() {\n" +
                "        var simulation = d3.forceSimulation().velocityDecay(0.8);\n" +
                "        simulation\n" +
                "            //   .force('x', 0.00111)\n" +
                "            //   .force('y', 0.000000001)\n" +
                "            .force('collide', d3\n" +
                "            .forceCollide()\n" +
                "            .radius(function (d) {\n" +
                "            return options.minCollision;\n" +
                "        })\n" +
                "            .iterations(2))\n" +
                "            .force('charge', d3.forceManyBody())\n" +
                "            .force('link', d3.forceLink().id(function (d) {\n" +
                "            return d.id;\n" +
                "        }))\n" +
                "            .force('center', d3.forceCenter(svg.node().parentElement.parentElement.clientWidth / 2, svg.node().parentElement.parentElement.clientHeight / 2))\n" +
                "            .on('tick', function () {\n" +
                "            tick();\n" +
                "        })\n" +
                "            .on('end', function () {\n" +
                "            if (options.zoomFit && !justLoaded) {\n" +
                "                justLoaded = true;\n" +
                "                zoomFit(2);\n" +
                "            }\n" +
                "        });\n" +
                "        return simulation;\n" +
                "    }\n" +
                "    function loadNeo4jData() {\n" +
                "        nodes = [];\n" +
                "        relationships = [];\n" +
                "        updateWithNeo4jData(options.neo4jData);\n" +
                "    }\n" +
                "    function loadNeo4jDataFromUrl(neo4jDataUrl) {\n" +
                "        nodes = [];\n" +
                "        relationships = [];\n" +
                "        d3.json(neo4jDataUrl, function (error, data) {\n" +
                "            if (error) {\n" +
                "                throw error;\n" +
                "            }\n" +
                "            updateWithNeo4jData(data);\n" +
                "        });\n" +
                "    }\n" +
                "    function merge(target, source) {\n" +
                "        Object.keys(source).forEach(function (property) {\n" +
                "            target[property] = source[property];\n" +
                "        });\n" +
                "    }\n" +
                "    function neo4jDataToD3Data(data) {\n" +
                "        var graph = {\n" +
                "            nodes: [],\n" +
                "            relationships: [],\n" +
                "        };\n" +
                "        data.results.forEach(function (result) {\n" +
                "            result.data.forEach(function (data) {\n" +
                "                data.graph.nodes.forEach(function (node) {\n" +
                "                    if (!contains(graph.nodes, node.id)) {\n" +
                "                        graph.nodes.push(node);\n" +
                "                    }\n" +
                "                });\n" +
                "                data.graph.relationships.forEach(function (relationship) {\n" +
                "                    relationship.source = relationship.startNode;\n" +
                "                    relationship.target = relationship.endNode;\n" +
                "                    graph.relationships.push(relationship);\n" +
                "                });\n" +
                "                data.graph.relationships.sort(function (a, b) {\n" +
                "                    if (a.source > b.source) {\n" +
                "                        return 1;\n" +
                "                    }\n" +
                "                    else if (a.source < b.source) {\n" +
                "                        return -1;\n" +
                "                    }\n" +
                "                    else {\n" +
                "                        if (a.target > b.target) {\n" +
                "                            return 1;\n" +
                "                        }\n" +
                "                        if (a.target < b.target) {\n" +
                "                            return -1;\n" +
                "                        }\n" +
                "                        else {\n" +
                "                            return 0;\n" +
                "                        }\n" +
                "                    }\n" +
                "                });\n" +
                "                for (var i = 0; i < data.graph.relationships.length; i++) {\n" +
                "                    if (i !== 0 &&\n" +
                "                        data.graph.relationships[i].source === data.graph.relationships[i - 1].source &&\n" +
                "                        data.graph.relationships[i].target === data.graph.relationships[i - 1].target) {\n" +
                "                        data.graph.relationships[i].linknum = data.graph.relationships[i - 1].linknum + 1;\n" +
                "                    }\n" +
                "                    else {\n" +
                "                        data.graph.relationships[i].linknum = 1;\n" +
                "                    }\n" +
                "                }\n" +
                "            });\n" +
                "        });\n" +
                "        return graph;\n" +
                "    }\n" +
                "    function randomD3Data(d, maxNodesToGenerate) {\n" +
                "        var data = {\n" +
                "            nodes: [],\n" +
                "            relationships: [],\n" +
                "        }, i, label, node, numNodes = ((maxNodesToGenerate * Math.random()) << 0) + 1, relationship, s = size();\n" +
                "        for (i = 0; i < numNodes; i++) {\n" +
                "            label = randomLabel();\n" +
                "            node = {\n" +
                "                id: s.nodes + 1 + i,\n" +
                "                labels: [label],\n" +
                "                properties: {\n" +
                "                    random: label,\n" +
                "                },\n" +
                "                x: d.x,\n" +
                "                y: d.y,\n" +
                "            };\n" +
                "            data.nodes[data.nodes.length] = node;\n" +
                "            relationship = {\n" +
                "                id: s.relationships + 1 + i,\n" +
                "                type: label.toUpperCase(),\n" +
                "                startNode: d.id,\n" +
                "                endNode: s.nodes + 1 + i,\n" +
                "                properties: {\n" +
                "                    from: Date.now(),\n" +
                "                },\n" +
                "                source: d.id,\n" +
                "                target: s.nodes + 1 + i,\n" +
                "                linknum: s.relationships + 1 + i,\n" +
                "            };\n" +
                "            data.relationships[data.relationships.length] = relationship;\n" +
                "        }\n" +
                "        return data;\n" +
                "    }\n" +
                "    function randomLabel() {\n" +
                "        var icons = Object.keys(options.iconMap);\n" +
                "        return icons[(icons.length * Math.random()) << 0];\n" +
                "    }\n" +
                "    function rotate(cx, cy, x, y, angle) {\n" +
                "        var radians = (Math.PI / 180) * angle, cos = Math.cos(radians), sin = Math.sin(radians), nx = cos * (x - cx) + sin * (y - cy) + cx, ny = cos * (y - cy) - sin * (x - cx) + cy;\n" +
                "        return { x: nx, y: ny };\n" +
                "    }\n" +
                "    function rotatePoint(c, p, angle) {\n" +
                "        return rotate(c.x, c.y, p.x, p.y, angle);\n" +
                "    }\n" +
                "    function rotation(source, target) {\n" +
                "        return (Math.atan2(target.y - source.y, target.x - source.x) * 180) / Math.PI;\n" +
                "    }\n" +
                "    function size() {\n" +
                "        return {\n" +
                "            nodes: nodes.length,\n" +
                "            relationships: relationships.length,\n" +
                "        };\n" +
                "    }\n" +
                "    function stickNode(d) {\n" +
                "        d.fx = d3.event.x;\n" +
                "        d.fy = d3.event.y;\n" +
                "    }\n" +
                "    function tick() {\n" +
                "        tickNodes();\n" +
                "        tickRelationships();\n" +
                "    }\n" +
                "    function tickNodes() {\n" +
                "        if (node) {\n" +
                "            node.attr('transform', function (d) {\n" +
                "                return 'translate(' + d.x + ', ' + d.y + ')';\n" +
                "            });\n" +
                "        }\n" +
                "    }\n" +
                "    function tickRelationships() {\n" +
                "        if (relationship) {\n" +
                "            relationship.attr('transform', function (d) {\n" +
                "                var angle = rotation(d.source, d.target);\n" +
                "                return 'translate(' + d.source.x + ', ' + d.source.y + ') rotate(' + angle + ')';\n" +
                "            });\n" +
                "            tickRelationshipsTexts();\n" +
                "            tickRelationshipsOutlines();\n" +
                "            tickRelationshipsOverlays();\n" +
                "        }\n" +
                "    }\n" +
                "    function tickRelationshipsOutlines() {\n" +
                "        relationship.each(function (relationship) {\n" +
                "            var rel = d3.select(this), outline = rel.select('.outline'), text = rel.select('.text'), bbox = text.node().getBBox(), padding = 3;\n" +
                "            outline.attr('d', function (d) {\n" +
                "                var center = { x: 0, y: 0 }, angle = rotation(d.source, d.target), textBoundingBox = text.node().getBBox(), textPadding = 5, u = unitaryVector(d.source, d.target), textMargin = {\n" +
                "                    x: (d.target.x - d.source.x - (textBoundingBox.width + textPadding) * u.x) * 0.5,\n" +
                "                    y: (d.target.y - d.source.y - (textBoundingBox.width + textPadding) * u.y) * 0.5,\n" +
                "                }, n = unitaryNormalVector(d.source, d.target), rotatedPointA1 = rotatePoint(center, { x: 0 + (options.nodeRadius + 1) * u.x - n.x, y: 0 + (options.nodeRadius + 1) * u.y - n.y }, angle), rotatedPointB1 = rotatePoint(center, { x: textMargin.x - n.x, y: textMargin.y - n.y }, angle), rotatedPointC1 = rotatePoint(center, { x: textMargin.x, y: textMargin.y }, angle), rotatedPointD1 = rotatePoint(center, { x: 0 + (options.nodeRadius + 1) * u.x, y: 0 + (options.nodeRadius + 1) * u.y }, angle), rotatedPointA2 = rotatePoint(center, { x: d.target.x - d.source.x - textMargin.x - n.x, y: d.target.y - d.source.y - textMargin.y - n.y }, angle), rotatedPointB2 = rotatePoint(center, {\n" +
                "                    x: d.target.x - d.source.x - (options.nodeRadius + 1) * u.x - n.x - u.x * options.arrowSize,\n" +
                "                    y: d.target.y - d.source.y - (options.nodeRadius + 1) * u.y - n.y - u.y * options.arrowSize,\n" +
                "                }, angle), rotatedPointC2 = rotatePoint(center, {\n" +
                "                    x: d.target.x - d.source.x - (options.nodeRadius + 1) * u.x - n.x + (n.x - u.x) * options.arrowSize,\n" +
                "                    y: d.target.y - d.source.y - (options.nodeRadius + 1) * u.y - n.y + (n.y - u.y) * options.arrowSize,\n" +
                "                }, angle), rotatedPointD2 = rotatePoint(center, {\n" +
                "                    x: d.target.x - d.source.x - (options.nodeRadius + 1) * u.x,\n" +
                "                    y: d.target.y - d.source.y - (options.nodeRadius + 1) * u.y,\n" +
                "                }, angle), rotatedPointE2 = rotatePoint(center, {\n" +
                "                    x: d.target.x - d.source.x - (options.nodeRadius + 1) * u.x + (-n.x - u.x) * options.arrowSize,\n" +
                "                    y: d.target.y - d.source.y - (options.nodeRadius + 1) * u.y + (-n.y - u.y) * options.arrowSize,\n" +
                "                }, angle), rotatedPointF2 = rotatePoint(center, {\n" +
                "                    x: d.target.x - d.source.x - (options.nodeRadius + 1) * u.x - u.x * options.arrowSize,\n" +
                "                    y: d.target.y - d.source.y - (options.nodeRadius + 1) * u.y - u.y * options.arrowSize,\n" +
                "                }, angle), rotatedPointG2 = rotatePoint(center, { x: d.target.x - d.source.x - textMargin.x, y: d.target.y - d.source.y - textMargin.y }, angle);\n" +
                "                return ('M ' +\n" +
                "                    rotatedPointA1.x +\n" +
                "                    ' ' +\n" +
                "                    rotatedPointA1.y +\n" +
                "                    ' L ' +\n" +
                "                    rotatedPointB1.x +\n" +
                "                    ' ' +\n" +
                "                    rotatedPointB1.y +\n" +
                "                    ' L ' +\n" +
                "                    rotatedPointC1.x +\n" +
                "                    ' ' +\n" +
                "                    rotatedPointC1.y +\n" +
                "                    ' L ' +\n" +
                "                    rotatedPointD1.x +\n" +
                "                    ' ' +\n" +
                "                    rotatedPointD1.y +\n" +
                "                    ' Z M ' +\n" +
                "                    rotatedPointA2.x +\n" +
                "                    ' ' +\n" +
                "                    rotatedPointA2.y +\n" +
                "                    ' L ' +\n" +
                "                    rotatedPointB2.x +\n" +
                "                    ' ' +\n" +
                "                    rotatedPointB2.y +\n" +
                "                    ' L ' +\n" +
                "                    rotatedPointC2.x +\n" +
                "                    ' ' +\n" +
                "                    rotatedPointC2.y +\n" +
                "                    ' L ' +\n" +
                "                    rotatedPointD2.x +\n" +
                "                    ' ' +\n" +
                "                    rotatedPointD2.y +\n" +
                "                    ' L ' +\n" +
                "                    rotatedPointE2.x +\n" +
                "                    ' ' +\n" +
                "                    rotatedPointE2.y +\n" +
                "                    ' L ' +\n" +
                "                    rotatedPointF2.x +\n" +
                "                    ' ' +\n" +
                "                    rotatedPointF2.y +\n" +
                "                    ' L ' +\n" +
                "                    rotatedPointG2.x +\n" +
                "                    ' ' +\n" +
                "                    rotatedPointG2.y +\n" +
                "                    ' Z');\n" +
                "            });\n" +
                "        });\n" +
                "    }\n" +
                "    function tickRelationshipsOverlays() {\n" +
                "        relationshipOverlay.attr('d', function (d) {\n" +
                "            var center = { x: 0, y: 0 }, angle = rotation(d.source, d.target), n1 = unitaryNormalVector(d.source, d.target), n = unitaryNormalVector(d.source, d.target, 50), rotatedPointA = rotatePoint(center, { x: 0 - n.x, y: 0 - n.y }, angle), rotatedPointB = rotatePoint(center, { x: d.target.x - d.source.x - n.x, y: d.target.y - d.source.y - n.y }, angle), rotatedPointC = rotatePoint(center, { x: d.target.x - d.source.x + n.x - n1.x, y: d.target.y - d.source.y + n.y - n1.y }, angle), rotatedPointD = rotatePoint(center, { x: 0 + n.x - n1.x, y: 0 + n.y - n1.y }, angle);\n" +
                "            return ('M ' +\n" +
                "                rotatedPointA.x +\n" +
                "                ' ' +\n" +
                "                rotatedPointA.y +\n" +
                "                ' L ' +\n" +
                "                rotatedPointB.x +\n" +
                "                ' ' +\n" +
                "                rotatedPointB.y +\n" +
                "                ' L ' +\n" +
                "                rotatedPointC.x +\n" +
                "                ' ' +\n" +
                "                rotatedPointC.y +\n" +
                "                ' L ' +\n" +
                "                rotatedPointD.x +\n" +
                "                ' ' +\n" +
                "                rotatedPointD.y +\n" +
                "                ' Z');\n" +
                "        });\n" +
                "    }\n" +
                "    function tickRelationshipsTexts() {\n" +
                "        relationshipText.attr('transform', function (d) {\n" +
                "            var angle = (rotation(d.source, d.target) + 360) % 360, mirror = angle > 90 && angle < 270, center = { x: 0, y: 0 }, n = unitaryNormalVector(d.source, d.target), nWeight = mirror ? 2 : -3, point = {\n" +
                "                x: (d.target.x - d.source.x) * 0.5 + n.x * nWeight,\n" +
                "                y: (d.target.y - d.source.y) * 0.5 + n.y * nWeight,\n" +
                "            }, rotatedPoint = rotatePoint(center, point, angle);\n" +
                "            return 'translate(' + rotatedPoint.x + ', ' + rotatedPoint.y + ') rotate(' + (mirror ? 180 : 0) + ')';\n" +
                "        });\n" +
                "    }\n" +
                "    function toString(d) {\n" +
                "        var s = d.labels ? d.labels[0] : d.type;\n" +
                "        s += ' (<id>: ' + d.id;\n" +
                "        Object.keys(d.properties).forEach(function (property) {\n" +
                "            s += ', ' + property + ': ' + JSON.stringify(d.properties[property]);\n" +
                "        });\n" +
                "        s += ')';\n" +
                "        return s;\n" +
                "    }\n" +
                "    function unitaryNormalVector(source, target, newLength) {\n" +
                "        var center = { x: 0, y: 0 };\n" +
                "        var vector = unitaryVector(source, target, newLength);\n" +
                "        return rotatePoint(center, vector, 90);\n" +
                "    }\n" +
                "    function unitaryVector(source, target, newLength) {\n" +
                "        var length = Math.sqrt(Math.pow(target.x - source.x, 2) + Math.pow(target.y - source.y, 2)) / Math.sqrt(newLength || 1);\n" +
                "        return {\n" +
                "            x: (target.x - source.x) / length,\n" +
                "            y: (target.y - source.y) / length,\n" +
                "        };\n" +
                "    }\n" +
                "    function updateWithD3Data(d3Data) {\n" +
                "        updateNodesAndRelationships(d3Data.nodes, d3Data.relationships);\n" +
                "    }\n" +
                "    function updateWithNeo4jData(neo4jData) {\n" +
                "        var d3Data = neo4jDataToD3Data(neo4jData);\n" +
                "        updateWithD3Data(d3Data);\n" +
                "    }\n" +
                "    function updateInfo(d) {\n" +
                "        clearInfo();\n" +
                "        if (d.labels) {\n" +
                "            appendInfoElementClass('class', d.labels[0]);\n" +
                "        }\n" +
                "        else {\n" +
                "            appendInfoElementRelationship('class', d.type);\n" +
                "        }\n" +
                "        appendInfoElementProperty('property', 'id', d.id);\n" +
                "        Object.keys(d.properties).forEach(function (property) {\n" +
                "            appendInfoElementProperty('property', property, d.properties[property]);\n" +
                "        });\n" +
                "    }\n" +
                "    function updateNodes(n) {\n" +
                "        Array.prototype.push.apply(nodes, n);\n" +
                "        node = svgNodes.selectAll('.node').data(nodes, function (d) {\n" +
                "            return d.id;\n" +
                "        });\n" +
                "        var nodeEnter = appendNodeToGraph();\n" +
                "        node = nodeEnter.merge(node);\n" +
                "    }\n" +
                "    function updateNodesAndRelationships(n, r) {\n" +
                "        updateRelationships(r);\n" +
                "        updateNodes(n);\n" +
                "        simulation.nodes(nodes);\n" +
                "        simulation.force('link').links(relationships);\n" +
                "    }\n" +
                "    function updateRelationships(r) {\n" +
                "        Array.prototype.push.apply(relationships, r);\n" +
                "        relationship = svgRelationships.selectAll('.relationship').data(relationships, function (d) {\n" +
                "            return d.id;\n" +
                "        });\n" +
                "        var relationshipEnter = appendRelationshipToGraph();\n" +
                "        relationship = relationshipEnter.relationship.merge(relationship);\n" +
                "        relationshipOutline = svg.selectAll('.relationship .outline');\n" +
                "        relationshipOutline = relationshipEnter.outline.merge(relationshipOutline);\n" +
                "        relationshipOverlay = svg.selectAll('.relationship .overlay');\n" +
                "        relationshipOverlay = relationshipEnter.overlay.merge(relationshipOverlay);\n" +
                "        relationshipText = svg.selectAll('.relationship .text');\n" +
                "        relationshipText = relationshipEnter.text.merge(relationshipText);\n" +
                "    }\n" +
                "    function version() {\n" +
                "        return VERSION;\n" +
                "    }\n" +
                "    function zoomFit(transitionDuration) {\n" +
                "        var bounds = svg.node().getBBox(), parent = svg.node().parentElement.parentElement, fullWidth = parent && parent.clientWidth ? parent.clientWidth : '100vw', fullHeight = parent && parent.clientHeight ? parent.clientHeight : '100vh', width = bounds.width, height = bounds.height, midX = bounds.x + width / 2, midY = bounds.y + height / 2;\n" +
                "        if (width === 0 || height === 0) {\n" +
                "            return;\n" +
                "        }\n" +
                "        svgScale = 0.85 / Math.max(width / fullWidth, height / fullHeight);\n" +
                "        svgTranslate = [fullWidth / 2 - svgScale * midX, fullHeight / 2 - svgScale * midY];\n" +
                "        svg.attr('transform', 'translate(' + svgTranslate[0] + ', ' + svgTranslate[1] + ') scale(' + svgScale + ')');\n" +
                "    }\n" +
                "    return {\n" +
                "        appendRandomDataToNode: appendRandomDataToNode,\n" +
                "        neo4jDataToD3Data: neo4jDataToD3Data,\n" +
                "        randomD3Data: randomD3Data,\n" +
                "        size: size,\n" +
                "        updateWithD3Data: updateWithD3Data,\n" +
                "        updateWithNeo4jData: updateWithNeo4jData,\n" +
                "        version: version,\n" +
                "        createGraph: createGraph,\n" +
                "    };\n" +
                "}\n" +
                "exports.default = Neo4jD3();\n"));
    }
}
